开发者问题收集

React:如果对象键值也是 true,则将 defaultChecked 设置为 true

2021-01-04
175

我有这个数据集,其中包含 amenities ,它也是对象中的对象:

{
    name: "California Maki Resort",
    price_per_night: 2804.0,
    description:
      "On a lush 16-hectare island with white-sand beaches, this relaxed resort is 5 km from the jetty in Cadiz Viejo, a village on the mainland.",
    address: "Cadiz Viejo",
    city: "Cadiz",
    amenities: 
      {
        tv: false,
        reservation: false,
        moderate_noise: true
    },
    image:
      "https://images.unsplash.com/photo-1591017403286-fd8493524e1e"
  }

如您所见,我在 amenities 下有 tvreservationmoderate_noise 子字段。在我的编辑度假村屏幕上,我需要从 amenities 中提取数据,并在值为 true 时将其设置为 defaultChecked 。所以我所做的是像这样映射对象:

{ 
            Object.keys(resort.amenities).reduce((result, key) => {
                return (
                    <div className="form-group"> 
            <div class="form-check">
                <input class="form-check-input" type="checkbox"
                name="tv"
                defaultChecked={result["tv"] === true}
                id="tv" value={true} ref={register} />
                <label class="form-check-label" for="tv">TV</label>
            </div>

            <div class="form-check">
                <input class="form-check-input" type="checkbox"
                name="reservation"
                defaultChecked={result["reservation"] === true}
                id="reservation" value={true} ref={register}/>
                <label class="form-check-label" for="reservation">Reservation</label>
            </div>

    )}
}

但这给了我一些错误,它无法读取 result["tv"] 我不确定是否正确检查了每个值是否为真,但我希望在复选框上选中它,如果数据库中的键(例如 tv)的值为真。请帮忙!

注意: resort.amenities 返回上述对象数据并且工作正常,我只是无法运行,因为我认为我通过此对象进行映射的方式不正确。

更新:只是为了给你完整的代码图片,它是:

import axios from 'axios'
import React, { useState, useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { useDispatch, useSelector } from 'react-redux'
import { store } from 'react-notifications-component'
import 'react-notifications-component/dist/theme.css'
import 'animate.css'
import  Message from '../components/Message'
import  Loader from '../components/Loader'
import { listResortDetails, updateResort } from '../actions/resortActions'
import { RESORT_UPDATE_RESET } from '../constants/resortConstants'

const ResortEditAdminScreen = ({ match, history }) => {

    const { register, errors, handleSubmit } = useForm()
    const resortId = match.params.id
    const [image, setImage] = useState('')
    const [uploading, setUploading] = useState(false)

    const dispatch = useDispatch()

    const resortDetails = useSelector(state => state.resortDetails)
    const { loading, error, resort } = resortDetails 

    const resortUpdate = useSelector(state => state.resortUpdate)
    const { 
        loading: loadingUpdate, 
        error: errorUpdate, 
        success: successUpdate 
    } = resortUpdate 

     useEffect(() => {

         console.log(resort.amenities)

        if(successUpdate){
            dispatch({ type: RESORT_UPDATE_RESET })
            history.push('/admin/resortsList')
            store.addNotification({
                title: 'Success!',
                message: 'Resort successfully updated.',
                type: 'success',                       
                container: 'top-right',               
                animationIn: ["animate__animated", "animate__fadeInRight"],   
                animationOut: ["animate__animated", "animate__fadeOutRight"],  
                dismiss: {
                  duration: 4000
                }
              })
        } else {

            if(!resort.name || resort._id !== resortId){
                dispatch(listResortDetails(resortId))
            }

              }
        }
     }, [dispatch, history, resortId, resort, successUpdate])

     const uploadFileHandler = async(e) => {
         const file = e.target.files[0]
         const formData = new FormData()
         formData.append('image', file)
         setUploading(true)

         try{
             const config = {
                 headers: {
                     'Content-Type': 'multipart/form-data'
                 }
             }
          
             const { data } = await axios.post('/api/upload', formData, config)
             setImage(data)
             setUploading(false)
         } catch(error){
            console.error(error)
            setUploading(false)
         }
     }



    const submitHandler = (data, e) => {
        e.preventDefault()
        const { name, pricePerNight, description, address, city, province, zipCode, phone, email, website, image, tv, reservation, moderateNoise, freeWifi, trendy, creditCard, bar, animals, kids } = data

        dispatch(updateResort({ 
            _id: resortId,
            name,
            price_per_night: pricePerNight,
            description,
            address,
            city,
            province,
            zip_code: zipCode,
            phone,
            email,
            website,
            image,
            amenities: {
                tv,
                reservation,
                moderate_noise: moderateNoise,
                free_wifi: freeWifi,
                trendy,
                credit_card: creditCard,
                bar,
                animals,
                kids
            }
        }))
    }



    return ( 
        <>
            <h1>Edit Resort</h1>
    { loadingUpdate && <Loader /> }    
    { errorUpdate && <Message variant='danger'>{errorUpdate}</Message> }   
    { loading ? <Loader /> : error ? <Message variant='danger'>{error}</Message> : (
            <form onSubmit={handleSubmit(submitHandler)}> 
            <div className="form-group"> 
            <label for="name">Name</label>
                        <input
                            type="text"
                            name="name"
                            defaultValue={resort.name}
                            className={`form-control ${errors.name ? 'is-invalid' : ''}`}
                            id="name"
                            ref={register({ required: true, minLength: 2, maxLength: 30 })}
                        />
                        { errors.name && errors.name.type ==='required' && <p className="text-danger">Name is required.</p> }
                        { errors.name && errors.name.type ==='minLength' && <p className="text-danger">Name is too short.</p> }
                        { errors.name && errors.name.type ==='maxLength' && <p className="text-danger">Name is exceeds maximum length.</p> }
            </div>
 
            <div className="form-group"> 
                    <label for="name">Price Per Night</label>
                    <input
                        type="text"
                        name="pricePerNight"
                        defaultValue={resort.price_per_night}
                        className={`form-control ${errors.pricePerNight ? 'is-invalid' : ''}`}
                        id="pricePerNight"
                        ref={register({ required: true, minLength: 2, maxLength: 5, pattern: /^-?(0|[1-9]\d*)?$/ })}
                    />
                    { errors.pricePerNight && errors.pricePerNight.type ==='required' && <p className="text-danger">Price is required.</p> }
                    { errors.pricePerNight && errors.pricePerNight.type ==='minLength' && <p className="text-danger">Price is too small.</p> }
                    { errors.pricePerNight && errors.pricePerNight.type ==='maxLength' && <p className="text-danger">Price exceeds maximum length.</p> }
                    { errors.pricePerNight && errors.pricePerNight.type ==='pattern' && <p className="text-danger">That is not a valid price.</p> }
            </div>

            <div className="form-group"> 
                <label for="description">Description</label>
                    <textarea
                    name="description"
                    defaultValue={resort.description}
                    className = {`form-control ${errors.description ? 'is-invalid' : ''}`}
                    id="description"
                    rows="5"
                    ref={register({ required: true, minLength: 100, maxLength: 500})}
                    />
                    {errors.description && errors.description.type === 'required' && <p className="text-danger">Description is required.</p>}
                    { errors.description && errors.description.type ==='minLength' && <p className="text-danger">Description is too short.</p> }
                    { errors.description && errors.description.type === 'maxLength' && <p className="text-danger">Description exceeds maximum length.</p>}
                    
            </div>

            <div className="form-group"> 
                <label for="address">Address</label>
                    <input
                        type="text"
                        name="address"
                        defaultValue={resort.address}
                        className= {`form-control ${errors.address ? 'is-invalid' : ''}`}
                        id="address"
                        ref={register({ required: true })}
                    />
                    { errors.address && errors.address.type ==='required' && <p className="text-danger">Address is required.</p> }
            </div>

            <div className="form-group"> 
                <label for="province">Province</label>
                    <input
                        type="text"
                        name="province"
                        defaultValue={resort.province}
                        className={`form-control ${errors.province ? 'is-invalid' : ''}`}
                        id="province"
                        ref={register({ required: true })}
                    />
                    { errors.province && errors.province.type ==='required' && <p className="text-danger">Province is required.</p> }
            </div>

            <div className="form-group"> 
                <label for="zip_code">Zip Code</label>
                    <input
                        type="text"
                        name="zipCode"
                        defaultValue={resort.zip_code}
                        className={`form-control ${errors.zipCode ? 'is-invalid' : ''}`}
                        id="zipCode"
                        ref={register({ required: true, minLength: 4,  maxLength: 4, pattern: /^[0-9]*$/ })}
                    />
                    { errors.zipCode && errors.zipCode.type === 'required' && <p className="text-danger">Zip Code is required.</p>}
                    {errors.zipCode && errors.zipCode.type === 'minLength' && <p className="text-danger">Zip Code must consist with 4 digits.</p>}
                    { errors.zipCode && errors.zipCode.type === 'maxLength' && <p className="text-danger">Zip Code must consist with 4 digits.</p>}
                    { errors.zipCode && errors.zipCode.type ==='pattern' && <p className="text-danger">Not a valid Zip Code.</p> }
            </div>

            <div className="form-group"> 
                <label for="city">City</label>
                    <input
                        type="text"
                        name="city"
                        defaultValue={resort.city}
                        className={`form-control ${errors.city ? 'is-invalid' : ''}`}
                        id="city"
                        ref={register({ required: true })}
                    />
                    { errors.city && errors.city.type ==='required' && <p className="text-danger">City is required.</p> }
            </div>

            <div className="form-group"> 
                <label for="phone">Phone</label>
                        <input
                            type="text"
                            name="phone"
                            defaultValue={resort.phone}
                            className={`form-control ${errors.phone ? 'is-invalid' : ''}`}
                            id="phone"
                            ref={register({ required: true, minLength: 10, maxLength: 13, pattern: /(^0|[89]\d{2}-\d{3}\-?\d{4}$)|(^0|[89]\d{2}\d{3}\d{4}$)|(^63[89]\d{2}-\d{3}-\d{4}$)|(^63[89]\d{2}\d{3}\d{4}$)|(^[+]63[89]\d{2}\d{3}\d{4}$)|(^[+]63[89]\d{2}-\d{3}-\d{4}$)|(^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$)/})}
                    />
                    { errors.phone && errors.phone.type ==='required' && <p className="text-danger">Phone is required.</p> }
                    { errors.phone && errors.phone.type ==='minLength' && <p className="text-danger">Phone length is too small.</p> }
                    { errors.phone && errors.phone.type ==='maxLength' && <p className="text-danger">Phone exceeds maximum length.</p> }
                    { errors.phone && errors.phone.type ==='pattern' && <p className="text-danger">Phone is not a valid phone.</p> }
            </div>

            <div className="form-group"> 
                <label for="email">Email</label>
                    <input
                        type="email"
                        name="email"
                        defaultValue={resort.email}
                        className={`form-control ${errors.email ? 'is-invalid' : ''}`}
                        id="email"
                        ref={register({ required: true, minLength: 8, maxLength: 30, pattern: /^\S+@\S+\.\S+$/ })}
                    />
                    { errors.email && errors.email.type ==='required' && <p className="text-danger">Email is required.</p> }
                    { errors.email && errors.email.type ==='minLength' && <p className="text-danger">Email length is too small.</p> }
                    { errors.email && errors.email.type ==='maxLength' && <p className="text-danger">Email exceeds maximum length.</p> }
                    { errors.email && errors.email.type ==='pattern' && <p className="text-danger">That is not a valid email.</p> }
            </div>

            <div className="form-group"> 
                <label for="website">Website</label>
                    <input
                        type="text"
                        name="website"
                        defaultValue={resort.website}
                        className={`form-control ${errors.website ? 'is-invalid' : ''}`}
                        id="website" 
                        ref={register({ required: true, pattern: /^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/ })}
                    />
                    { errors.website && errors.website.type === 'required' && <p className="text-danger">Website is required.</p>}
                    { errors.website && errors.website.type ==='pattern' && <p className="text-danger">Not a valid website url.</p> }
            </div>

            <div className="form-group"> 
               <label for="uploadImage">Upload Image</label>
                <input 
                type="file" 
                className="form-control-file"
                id="uploadImage" 
                onChange={uploadFileHandler}
                ref={register} 
                />
            </div>
            { uploading && <Loader /> }
            
            
            { 
            Object.keys(resort.amenities).reduce((result, key) => {
                return (
                    <div className="form-group"> 
            <div class="form-check">
                <input class="form-check-input" type="checkbox"
                name="tv"
                defaultChecked={result["tv"] === true}
                id="tv" value={true} ref={register} />
                <label class="form-check-label" for="tv">TV</label>
            </div>

            <div class="form-check">
                <input class="form-check-input" type="checkbox"
                name="reservation"
                defaultChecked={resort.amenities.reservation === true}
                id="reservation" value={true} ref={register}/>
                <label class="form-check-label" for="reservation">Reservation</label>
            </div>
        </>
    )}

export default ResortEditAdminScreen

更新:它显示此错误 TypeError:无法读取未定义的属性“tv”

3个回答

您不需要使用 Object.keysreduce ,因为您可以直接从 amenities 对象获取值。

return (
  <div className="form-group">
    <div class="form-check">
      <input
        class="form-check-input"
        type="checkbox"
        name="tv"
        defaultChecked={resort.amenities.tv === true}
        id="tv"
        value={true}
        ref={register}
      />
      <label class="form-check-label" for="tv">
        TV
      </label>
    </div>

    <div class="form-check">
      <input
        class="form-check-input"
        type="checkbox"
        name="reservation"
        defaultChecked={resort.amenities.reservation === true}
        id="reservation"
        value={true}
        ref={register}
      />
      <label class="form-check-label" for="reservation">
        Reservation
      </label>
    </div>
  </div>
)
Mark Skelton
2021-01-04

像这样使用 JS 地图:

return Object.keys(resort.amenities).map((name, index) => {
      return (
        <label key={index}>
          <input                
            type="checkbox"
            checked={resort.amenities[name]}                
          />
          {name}
        </label>
      );
});
Navoneel Talukdar
2021-01-04

当您使用 Object.keys() 时,您实际上是在创建一个键数组,但您无权访问这些值,例如:

console.log(Object.keys(resort.amenities)) ///[tv,reservation,moderate_noise]

而要访问这些值,您必须使用 Object.values()

console.log(Object.values(resort.amenities)) ///[false,false,true]

而对于您的代码,当使用 reduce

Object.keys(resort.amenities).reduce((result, key) => {
 console.log(result) ///tv , undefined
}

因此,它会显示错误 TypeError: Cannot read property 'tv' of undefined

我不明白为什么您要将其转换为数组,而它可以直接使用!

我建议这样做

<div className="form-group"> 
            <div class="form-check">
                <input class="form-check-input" type="checkbox"
                name="tv"
                defaultChecked={resort ?resort.amenities.tv === true :false}
                id="tv" value={true} ref={register} />
                <label class="form-check-label" for="tv">TV</label>
            </div>

            <div class="form-check">
                <input class="form-check-input" type="checkbox"
                name="reservation"
               defaultChecked={resort ?resort.amenities.reservation === true :false}
                id="reservation" value={true} ref={register}/>
                <label class="form-check-label" for="reservation">Reservation</label>
            </div>
zahra zamani
2021-01-04