React Native:从其他组件更改状态

时间:2020-10-10 11:17:27

标签: reactjs react-native

我对React-Native很陌生。我有一个屏幕,该屏幕以json格式从我的服务中获取信息,并在此之后显示数据。在该屏幕上,我有一个组件“日历”,用户可以从中获取另一个日期。我不知道如何从该组件更新预测状态。

这是我的主屏幕:

export default function HomeScreen({ navigation }) {

  const [predictions, setPredictions] = useState([]);
  const [params, setParams] = useState({
    lang: 'en',
    date: '2020-10-11',
    sport: 'soccer'
  });

  useEffect( () => {
    loadPredictions();
  }, []);

  const loadPredictions = async () => {
    const response = await PredictionsApi.getPredictions({params});
    // console.log(response.data);
    setPredictions(response.data);
  }

  return (
    <View style={styles.main}>
        <View style={styles.container}>
          <Calendar />
          ...
        </View>
    </View>
}

这是我的日历组件:

function renderDates({props}) {
    const dates = [];
    for(let i=-2;i<4;++i) {
        var currentDate = new Date(new Date().getTime() + 24 * 60 * 60 * i * 1000);
        dates.push(
            <TouchableOpacity style={styles.dates} onPress={()=> props.setPredictions({
                lang: 'en',
                date: '2020-02-01',
                sport: 'tennis',
            })
            }>
                <Text style={styles.selected}>{Moment(currentDate).format('ddd')}{"\n"}{Moment(currentDate).format('DD')}</Text>
            </TouchableOpacity>
        );
    }
    return dates;
}

export default function Calendar({props}) {
    return (
        <View style={styles.calendarContainer}>
            ...
            <View style={styles.second}>
                {renderDates({props})}
            </View>
        </View>
    );
}

2 个答案:

答案 0 :(得分:0)

您应该使用setState并先阅读文档

https://reactjs.org/docs/react-component.html#setstate

答案 1 :(得分:0)

因此,我建议您在这段代码中做很多事情。但是,要回答您的问题,您可以向下传递setPredictions函数作为道具,然后在props.setPredictions()组件中使用Calendar进行调用。

这个想法的一个简单例子是:

const Parent = () => {
  const parentFunction = () => console.log('Hello from parent');

  return <Child parentFunction={parentFunction} />;
};


// clicking the div in this child will call the function defined in Parent
const Child = ({parentFunction}) => <div onClick={parentFunction}>Click me</div>;

对于在父级中设置状态的所有函数,您都可以使用相同的原理。

我会在这里停止。如果您对此有疑问,请询问。如果您想对其余的代码提供进一步的建议,请告诉我。谢谢。

这是我的尝试,以解决您对代码的某些担忧。我认为您的问题是由于错误地破坏了道具造成的,而且您似乎实际上并没有在子组件的任何位置设置预测或调用API。我希望这是有道理的:

// use const instead of function - more conventional
const HomeScreen = ({navigation}) => {
  const [predictions, setPredictions] = useState([]);
  const [params, setParams] = useState({
    lang: 'en',
    date: '2020-10-11',
    sport: 'soccer',
  });

  useEffect(() => {
    loadPredictions();
  }, []);

  const loadPredictions = async () => {
    const response = await PredictionsApi.getPredictions({params});
    // console.log(response.data);
    setPredictions(response.data);
  };

  return (
    <View style={styles.main}>
      <View style={styles.container}>
        {/* Pass load predictions and setParams to Calendar as props */}
        <Calendar loadPredictions={loadPredictions} setParams={setParams} />
      </View>
    </View>
  );
};

// destructuring should be used to get the individual props. If you put {props} then
// the implication is you would be using `props.props.theActualProp`
// so either remove the curly braces or destructure the actual props
// you want to use
const Calendar = props => (
  <View style={styles.calendarContainer}>
    <View style={styles.second}>
      {/* pass all the props down to Dates component */}
      {/* I also changed this to an element, since there is no reason to do otherwise */}
      <Dates {...props} />
      {/* I added a button here so you can actually reload the predictions */}
      <TouchableOpacity onPress={props.loadPredictions}>Load new predictions</TouchableOpacity>
    </View>
  </View>
);

// only destructure if you are pulling individual props OUT of the `props` object
const Dates = props => {
  // don't use for loops inside a function like this... it's cleaner to use the `map` method
  // on an array

  // cache the current time once per render if you need to
  const cachedTime = new Date().getTime();

  // I'm not sure why these particular numbers are important, or what you're trying to do here
  // I've preserverd the behaviour from your for loop, but depending on what you're trying
  // to achieve there is probably a more sensible solution to this
  return [-2, -1, 0, 1, 2, 3, 4].map(val => {
    const rowDate = new Date(cachedTime + 24 * 60 * 60 * val * 1000);

    return (
      <TouchableOpacity
        // add a key when mapping over an array
        key={val}
        style={styles.dates}
        onPress={() =>
          // I changed this to setParams. I think this is what you meant, since
          // setPredictions should only be form your API response?
          props.setParams({
            lang: 'en',
            date: '2020-02-01',
            sport: 'tennis',
          })
        }
      >
        <Text style={styles.selected}>
          {Moment(rowDate).format('ddd')}
          {'\n'}
          {Moment(rowDate).format('DD')}
        </Text>
      </TouchableOpacity>
    );
  });
};