我正在构建一个简单的应用程序,该应用程序可通过搜索到的输入值使用d3图形显示数据。
export const Search = () => {
const [country, setCountry] = React.useState('');
const [weatherData, setWeatherData] = React.useState([]);
const changeText = e => {
setCountry(e.target.value)
}
const searchCountry = () => {
fetch(`https://apiweatherhistory/dayone/country/${country}`).then(res => res.json().then(data => {
setWeatherData(weatherData)
}))
}
const svg = d3.select('.weatherSearch')
.append('svg')
.attr('width', 960)
.attr('height', 500)
.style('background', 'black')
return (
<div>
<input type='text' onChange={(e) => changeText(e)} value={country} />
<button onClick={searchCountry}>Search</button>
<div className='weatherSearch' />
</div>
)
}
安装组件后,d3会将svg元素附加到div标签名称 weatherSearch 。
问题是组件在渲染svg标签两次之前渲染了两次。但是当我注释掉两个状态初始化时,
const [country, setCountry] = React.useState('');
const [weatherData, setWeatherData] = React.useState([]);
该组件仅渲染一次,并绘制一次svg标签。
输入或点击交互尚未发生,这意味着甚至没有使用两种状态更改方法(setCountry,setWeatherData)。
并且搜索组件是index.js的根组件,因此父组件无法触发重新呈现。
为什么会这样?只有初始化状态才能触发重新渲染吗?
答案 0 :(得分:1)
我怀疑这是因为附加svg在功能组件主体中,因此每次“渲染”组件时都会执行该svg。我所说的“渲染”是指当React框架在“渲染”阶段渲染virtualDOM树以计算差异时。这与将计算的DOM刷新到 actual DOM以及运行效果和其他生命周期功能时的“提交”阶段不同。通过几乎任何次数的反应,可以暂停,中止和重新启动“渲染”阶段。
我会将这个逻辑放在带有空依赖性数组的useEffect
挂钩中,以便它在组件安装上运行。
export const Search = () => {
const [country, setCountry] = React.useState('');
const [weatherData, setWeatherData] = React.useState([]);
const changeText = e => {
setCountry(e.target.value)
}
const searchCountry = () => {
fetch(`https://apiweatherhistory/dayone/country/${country}`).then(res => res.json().then(data => {
setWeatherData(weatherData)
}))
}
useEffect(() => {
const svg = d3.select('.weatherSearch')
.append('svg')
.attr('width', 960)
.attr('height', 500)
.style('background', 'black');
}, []);
return (
<div>
<input type='text' onChange={(e) => changeText(e)} value={country} />
<button onClick={searchCountry}>Search</button>
<div className='weatherSearch' />
</div>
)
}
答案 1 :(得分:0)
您不能确定组件将被重新渲染多少次。它不是确定性算法,而是启发式算法。
此外,将受控虚拟DOM与不受控制的D3混合也不是一个好主意。请看看这个钩子https://en.reactjs.org/docs/hooks-reference.html#uselayouteffect 以及该API https://en.reactjs.org/docs/portals.html,以了解如何实现这种情况。
但是恕我直言,最好将SVG部分由React而不使用D3控制。您可以直接在虚拟DOM中使用SVG标签。
其他提示:
处理器可以由useCallback缓存。 例如:
const onChange = useCallback(
({ target: { value } }) => setCountry(value),
[setCountry],
);
<input onChange={onChangeText} />
此外,最好为处理程序命名onSomeEvent