javascript - 在 useEffect 中设置 setState 导致状态更改延迟的问题
问题描述
我正在使用 React Hooks 和 Redux 处理这个滑块效果。我的代码如下:
const Barchart = ({chartData}) => {
let newArray = []
let len = chartData.length
const [XArray,setXArray]=useState([chartData])
const [Yarray,setYArray]=useState(chartData[len-1].anArray) //so the initial state here should be an empty array
// const d3Container = useRef(null);
useEffect(()=>{
let len = chartData.length
console.log(chartData.length)
newArray = chartData[len-1].anArray
setYArray(newArray)
if(newArray.length!==0){
const height = 70 //height of the actual chart, different than the svg element
const width = 26.5*newArray.length //width of the actual chart, different than the svg element
const svg = d3.select('.svg-canvas')
svg.selectAll("*").remove()
var x = d3.scaleLinear().domain([0,7]).range([0,width])
var y = d3.scaleLinear().domain([0,d3.max(Yarray)]).range([height,0])
var xAxis = d3.axisBottom(x).ticks(8)
var yAxis = d3.axisLeft(y).ticks(5)
//locate the chart in the middle of the svg frame: 800/2 - width/2
var chartGroup = svg.append('g').attr('transform','translate('+(400 - width/2)+',300)')
chartGroup.selectAll("rect").data(Yarray).enter().append("rect")
.attr("height",(d,i)=>d*3)
.attr("width","15")
.attr("fill","blue")
.attr('x',(d,i)=>26.5*i)
.attr('y',(d,i)=>height-d*3)
chartGroup.selectAll('text').data(Yarray).enter().append("text")
.attr('font-size',15)
.attr('x',(d,i)=>26.5*i)
.attr('y',(d,i)=>height-5-d*3+2)
.text((d,i)=>d)
chartGroup.append('g').attr('class','axis y')
// .attr('transform','translate(500,76)')
.call(yAxis)
chartGroup.append('g').attr('class','axis x')
.attr('transform','translate(0,'+height+')')
.call(xAxis)
}
},[chartData])
const newArrayFunc = (a) =>{
setYArray(a)
}
return(
<div id='chart-container'>
<h3>Bar Chart</h3>
<svg className="svg-canvas" width="800px" height="400px"></svg>
</div>
)
}
const mapStateToProps = state => ({
chartData:state.chartChange
});
export default connect(mapStateToProps)(Barchart)
如您所见,即使我在 useEffect 中设置了 setYArray,它的异步功能也会阻止 Yarray 立即更新。每当我有一个来自 的新数组时chartData
,d3 条形图都会使用以前的数组。
我在这里试图实现的目标是,每当 chartData 中的数组更新时,更新后的数组将立即在 d3 条形图中使用。
我应该在这里做什么?
解决方案
选项1
继续使用与newArray
更新状态相同的值
const Barchart = ({ chartData }) => {
let newArray = [];
let len = chartData.length;
const [XArray, setXArray] = useState([chartData]);
const [Yarray, setYArray] = useState(chartData[len - 1].anArray); //so the initial state here should be an empty array
// const d3Container = useRef(null);
useEffect(() => {
let len = chartData.length;
console.log(chartData.length);
newArray = chartData[len - 1].anArray;
setYArray(newArray);
if (newArray.length) { // <-- use in-scope newArray value
const height = 70; //height of the actual chart, different than the svg element
const width = 26.5 * newArray.length; //width of the actual chart, different than the svg element
const svg = d3.select(".svg-canvas");
svg.selectAll("*").remove();
var x = d3.scaleLinear().domain([0, 7]).range([0, width]);
var y = d3
.scaleLinear()
.domain([0, d3.max(newArray)]) // <-- use in-scope newArray value
.range([height, 0]);
var xAxis = d3.axisBottom(x).ticks(8);
var yAxis = d3.axisLeft(y).ticks(5);
//locate the chart in the middle of the svg frame: 800/2 - width/2
var chartGroup = svg
.append("g")
.attr("transform", "translate(" + (400 - width / 2) + ",300)");
chartGroup
.selectAll("rect")
.data(newArray) // <-- use in-scope newArray value
.enter()
.append("rect")
.attr("height", (d, i) => d * 3)
.attr("width", "15")
.attr("fill", "blue")
.attr("x", (d, i) => 26.5 * i)
.attr("y", (d, i) => height - d * 3);
chartGroup
.selectAll("text")
.data(newArray) // <-- use in-scope newArray value
.enter()
.append("text")
.attr("font-size", 15)
.attr("x", (d, i) => 26.5 * i)
.attr("y", (d, i) => height - 5 - d * 3 + 2)
.text((d, i) => d);
chartGroup
.append("g")
.attr("class", "axis y")
// .attr('transform','translate(500,76)')
.call(yAxis);
chartGroup
.append("g")
.attr("class", "axis x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
}
}, [chartData]);
const newArrayFunc = (a) => {
setYArray(a);
};
return (
<div id="chart-container">
<h3>Bar Chart</h3>
<svg className="svg-canvas" width="800px" height="400px"></svg>
</div>
);
};
选项 2
更新状态并使用第二个效果更新 d3
const Barchart = ({ chartData }) => {
let newArray = [];
let len = chartData.length;
const [XArray, setXArray] = useState([chartData]);
const [Yarray, setYArray] = useState(chartData[len - 1].anArray); //so the initial state here should be an empty array
// const d3Container = useRef(null);
useEffect(() => {
let len = chartData.length;
console.log(chartData.length);
newArray = chartData[len - 1].anArray;
setYArray(newArray);
}, [chartData]);
useEffect(() => {
if (Yarray.length) {
const height = 70; //height of the actual chart, different than the svg element
const width = 26.5 * Yarray.length; //width of the actual chart, different than the svg element
const svg = d3.select(".svg-canvas");
svg.selectAll("*").remove();
var x = d3.scaleLinear().domain([0, 7]).range([0, width]);
var y = d3
.scaleLinear()
.domain([0, d3.max(Yarray)])
.range([height, 0]);
var xAxis = d3.axisBottom(x).ticks(8);
var yAxis = d3.axisLeft(y).ticks(5);
//locate the chart in the middle of the svg frame: 800/2 - width/2
var chartGroup = svg
.append("g")
.attr("transform", "translate(" + (400 - width / 2) + ",300)");
chartGroup
.selectAll("rect")
.data(Yarray)
.enter()
.append("rect")
.attr("height", (d, i) => d * 3)
.attr("width", "15")
.attr("fill", "blue")
.attr("x", (d, i) => 26.5 * i)
.attr("y", (d, i) => height - d * 3);
chartGroup
.selectAll("text")
.data(Yarray)
.enter()
.append("text")
.attr("font-size", 15)
.attr("x", (d, i) => 26.5 * i)
.attr("y", (d, i) => height - 5 - d * 3 + 2)
.text((d, i) => d);
chartGroup
.append("g")
.attr("class", "axis y")
// .attr('transform','translate(500,76)')
.call(yAxis);
chartGroup
.append("g")
.attr("class", "axis x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
}
}, [Yarray]);
const newArrayFunc = (a) => {
setYArray(a);
};
return (
<div id="chart-container">
<h3>Bar Chart</h3>
<svg className="svg-canvas" width="800px" height="400px"></svg>
</div>
);
};
推荐阅读
- c# - 如何实现像圆圈一样的导航?
- automated-tests - 万一 cypress 找到路径并被 not.exist 错误卡住
- java - 在 SpringBoot 应用程序中使用单向 @ManyToOne 关系更新实体时出现问题
- python - Python中基于类别的测验问题数量
- flutter - 如何在不使用 ffmpeg_kit_flutter 的情况下向视频添加音频?
- delphi-10.4-sydney - 本机 IDE 调用堆栈窗口在崩溃时始终为空
- sql - 将列更新为重复
- javascript - DataTables - 高级搜索/列过滤器?
- firebase - 如何在 Firestore 数据库中建模这种情况?
- awk - 将两列合并为新列并打印所有列