【问题标题】:Within a parent component, is there any way I can access a prop from a child component?在父组件中,有什么方法可以从子组件访问道具?
【发布时间】:2021-04-21 01:57:58
【问题描述】:

我在构建 React 项目时经常遇到一个问题 - 我需要在组件中添加一个 prop,但由于它违反了 props 的单向流而无法访问它。

这是我现在遇到的具体问题: 在我的CafeReviews.jsx 组件中,我需要访问一条数据averageRating - 但是,此属性包含在子组件Review.jsx 中。
所以我需要在CafeReviews 中访问这些数据,这样我就可以将它作为道具传递给<CafeHeader/>

有什么想法可以解决这个问题,而无需重组我的组件?

这是父组件CafeReviews.jsx

import React,{useState, useEffect} from 'react'
import axios from 'axios'
import Review from './Review'
import CafeHeader from './CafeHeader'

const CafeReviews = ({ match }) => {
  const [cafe, setCafe] = useState([]);
  const [reviews, setReviews] = useState([]);

  useEffect(() => {
    axios.get(`/api/cafe/${match.params.id}`).then((result) => {
      setCafe(result.data);
    })
    axios.get("http://localhost:5000/api/all-reviews")
      .then((review) => {
        setReviews(review.data);
      })
      .catch((err) => {
        console.log(err);
      })
  }, [])

  let filteredReviews = reviews.filter((review) => {
    return review.cafeName === cafe.cafeName;
  });


  return (
    <div>
      <CafeHeader cafe={cafe} />
      <div className="reviews-container">
      <Review reviews={filteredReviews} />
      </div>
    </div>
  )
}

export default CafeReviews

...还有一个子组件Review.jsx,包含我要访问的averageRating 属性:

import React from 'react'
import axios from 'axios'
import {convertToStars, averageStarRating} from '../helperFunctions'

const Review = (props) => {
  const { reviews } = props;

  const handleClick = (id) => {
    axios
      .delete(`/api/reviews/${id}`)
      .then(() => {
        console.log("review successfully deleted");
      })
      .catch((err) => {
        console.log(err);
      })
  }

  return (
    <div>
      {
      reviews.map((review) => {
        const { title, userName, blurb, stars, _id } = review;

        const starRating = convertToStars(stars)
        const averageRating = averageStarRating(reviews)

        return (
          <div  className = 'review-container'>
            <h1>{title}</h1>
            {starRating.map((item) => {
              return item
            })}
            <h2>{`Review by: ${userName}`}</h2>
            <p>{blurb}</p>
            <button onClick={() => handleClick(_id)}>Delete</button>
          </div>
        )
      })
      }
    </div>
  )
}

export default Review

【问题讨论】:

标签: reactjs


【解决方案1】:

在您的父元素 CafeReviews 中设置一个状态,并传递一个函数作为道具来更改该状态。

import React,{useState, useEffect, useCallback} from 'react'
import axios from 'axios'
import Review from './Review'
import CafeHeader from './CafeHeader'

const CafeReviews = ({ match }) => {
  const [cafe, setCafe] = useState([]);
  const [reviews, setReviews] = useState([]);
  // change here
  const [infoFromChild, setInfo] = useState(null);
  const getDataFromChild = useCallback(data => setInfo(data),[]);
//
  useEffect(() => {
    axios.get(`/api/cafe/${match.params.id}`).then((result) => {
      setCafe(result.data);
    })
    axios.get("http://localhost:5000/api/all-reviews")
      .then((review) => {
        setReviews(review.data);
      })
      .catch((err) => {
        console.log(err);
      })
  }, [])

  let filteredReviews = reviews.filter((review) => {
    return review.cafeName === cafe.cafeName;
  });


  return (
    <div>
      <CafeHeader cafe={cafe} getDataFromChild={getDataFromChild}/>
      <div className="reviews-container">
      <Review reviews={filteredReviews} />
      </div>
    </div>
  )
}
import React from 'react'
import axios from 'axios'
import {convertToStars, averageStarRating} from '../helperFunctions'

const Review = (props) => {
  const { reviews, getDataFromChild } = props;

  const handleClick = (id) => {
    axios
      .delete(`/api/reviews/${id}`)
      .then(() => {
        console.log("review successfully deleted");
      })
      .catch((err) => {
        console.log(err);
      })
  }

  return (
    <div>
      {
      reviews.map((review) => {
        const { title, userName, blurb, stars, _id } = review;

        const starRating = convertToStars(stars)
        const averageRating = averageStarRating(reviews)
        //added here
        getDataFromChild(averageRating);
        return (
          <div  className = 'review-container'>
            <h1>{title}</h1>
            {starRating.map((item) => {
              return item
            })}
            <h2>{`Review by: ${userName}`}</h2>
            <p>{blurb}</p>
            <button onClick={() => handleClick(_id)}>Delete</button>
          </div>
        )
      })
      }
    </div>
  )
}

export default Review

【讨论】:

    【解决方案2】:

    React 设计时考虑了单向流,因此最好将您的 fetch 提升到更高的级别,并将函数和数据作为 props 传递给子组件。

    但是有一些方法可以访问父组件中的子组件数据。

    1. 状态管理 例如,Redux 可用于集中应用程序的状态。因此几乎所有组件都可以访问该状态。

    2. 反应上下文 API

    但是对于小型应用程序,使用 redux 配置可能有点矫枉过正,有一些更简单的东西,例如immer-store,但它可能会在小二人组中对您的支持和社区问题造成伤害。 React 方式本身为这些场景提供了一种称为context 的方法。这是一个很棒的article,关于如何在一个简单的项目中有效地使用反应上下文

    1. 反应使用ImperativeHandle
    const Child = (props, ref) => {
      const [state, setState] = React.useState(initialState)
    
      useEffect(() => { /*save fetched items in state */}, [])
    
      const getHandlerFunctions = () => ({
        getState: () => state,
        otherCallbacks: () => otherFallback(state, ...args)
      })
    
      React.useImperativeHandle(ref, getHandlerFunctions, [dependencies])
    
      return <div data-type="your-child-component" />
    }
    
    export default  React.forwardRef(Child);
    

    然后像这样在父组件中抓取你的数据

    const Parent = () => {
     const childRef = React.useRef()
    
      const callback = () => {
        const { current: child } = childRef
        if (!child) return
        child.getState() // will return updated state
        child.otherCallbacks() 
    
      }
    }
    
    1. js 让 这甚至可以帮助您在反应组件之外使用此功能
    
    let _callback = () => {}
    
    const Child = () => {
      const [state, setState] = React.useState(initialState)
    
      // you can change dependensis by your need
      React.useEffect(() => {
        _callback = (...args) => {
          console.log('do anything with', state, ...args)
        }
    
        return () => {
          _callback = () => {}
        }
      })
    
    }
    
    export const struct = {
      get callback() {
        return _callback
      },
    }
    

    您可以在Use callback definition of a functional component outside the component React UserContext: Conditional in useEffect is being ignored 中阅读有关这些解决方案的更多信息

    【讨论】:

      猜你喜欢
      • 2020-12-21
      • 1970-01-01
      • 1970-01-01
      • 2016-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多