React Native组件不会在状态更改时重新呈现

时间:2019-11-14 14:00:06

标签: reactjs react-native react-hooks

在接收到更改其状态的新道具后,我无法重新渲染组件。我对React Native和使用钩子都是新手,所以请多多包涵。这是有问题的组件:

function AreaChart(timeScale) {

  const width = Dimensions.get('window').width;
  const height = Dimensions.get('window').height;
  const [areaChartJS, setAreaChartJS] = useState(chartJS.areaChart(width, timeScale.timeScale));

  useEffect(() => {
    console.log(timeScale.timeScale);
    setAreaChartJS(chartJS.areaChart(width, timeScale.timeScale));
  }, [areaChartJS, timeScale]);

  return(
    <View>
      <WebView
        originWhitelist={['*']}
        useWebKit={true}
        source={{ html: areaChartHtml }}
        domStorageEnabled={true}
        javaScriptEnabled={true}
        style={styles.WebViewStyle}
        injectedJavaScript={areaChartJS}
      />
      <Text>{timeScale.timeScale}</Text>
    </View>
  );
}

这需要一些解释。我使用的是仅用于Web的图表库,因此必须在此处使用WebView进行渲染。 areaChartHtml和areaChartJS是HTML和JS代码,由于它们都是本地的,因此将注入到WebView中。这两个都是WebView解析和呈现的字符串。我在另一个名为chartJS的文件中包含了JS代码,在传递设备的宽度和timeScale时会调用该文件,以便根据这些变量动态呈现图表。

问题是,更改timeScale后,该组件不会重新渲染,而是继续使用在初始渲染期间从父组件传递的初始timeScale。在useEffect挂钩中,我记录了timeScale并获得了正确的值,但是即使使用新的timeScale属性通过setAreaChartJS函数更改状态,也不会触发重新渲染。 WebView下的<Text>元素还显示了timeScale的正确实时值,甚至从外部chartJS文件记录时也显示了正确的值,但是新的JS代码并未注入到WebView中。 <Text>使用新值进行更新的事实告诉我,组件正在被重新渲染,但是WebView并未从状态中提取新的areaChartJS。

当组件完全卸载并再次安装时,timeScale将被正确注册,并相应地呈现图表。在没有完全重新安装组件的情况下如何实现?

1 个答案:

答案 0 :(得分:0)

我已经设法通过将ref放在WebView上并在.reload()中调用其useEffect方法来获得所需的行为。我不知道WebView的内部工作原理,但是我假设它会将注入的JS的初始值保存在某个地方,即使正在重新渲染组件,也不会注入新的值,除非您以这种方式强制重新加载。该组件现在的外观如下:

function AreaChart(timeScale) {

  const width = Dimensions.get('window').width;
  const height = Dimensions.get('window').height;
  const [areaChartJS, setAreaChartJS] = useState(chartJS.areaChart(width, timeScale.timeScale));
  const [currTimeScale, setCurrTimeScale] = useState('1h');

  useEffect(() => {
    setAreaChartJS(chartJS.areaChart(width, timeScale.timeScale));
    if (currTimeScale !== timeScale.timeScale) {
      WebViewRef.reload();
      setCurrTimeScale(timeScale.timeScale);
    }
  }, [timeScale]);

  return(
    <View style={{flex: 1, height: 300}}>
      <WebView
        ref={WVref => (WebViewRef = WVref)}
        originWhitelist={['*']}
        useWebKit={true}
        source={{ html: areaChartHtml }}
        domStorageEnabled={true}
        javaScriptEnabled={true}
        style={styles.WebViewStyle}
        injectedJavaScript={areaChartJS}
      />
    </View>
  );
}