useEffect 中的 setState 不适用于 React JS 中的 First Render
setState inside useEffect not working on First Render in React JS
我正在构建一个使用 React Awesome Slider 的 ReactJS 组件。
我要创建的是一个滑块,下面有一个描述 div,它会更改文本,然后我更改幻灯片。
现在,我找到了让它工作的方法,但我对对象的 setState 有疑问,这是代码。
滑块:
const AutoplaySlider = withAutoplay(AwesomeSlider);
const StaticSlider = ({slider}) => {
var images = "";
var length=0;
const [current, setCurrent] = useState(0);
const [title, setTitle] = useState([]);
const [description, setDescription] = useState([]);
switch (slider) {
case 'portfolio_sviluppo_software':
images = portfolio_description.sviluppo_software;
length= portfolio_description.sviluppo_software.length;
break;
case 'portfolio_domotica':
images = portfolio_description.domotica;
length= portfolio_description.domotica.length;
break;
case 'portfolio_digital_signage':
images = portfolio_description.digital_signage;
length= portfolio_description.digital_signage.length;
break;
case 'portfolio_ricerca_e_sviluppo':
images = portfolio_description.ricerca_e_sviluppo;
length= portfolio_description.ricerca_e_sviluppo.length;
break;
}
useEffect(
() => {
setTitle(
images.map(
(slide) => (slide.title)
)
);
setDescription(
images.map(
(desc) => (desc.data)
)
);
}, [images]
);
return(
<div>
<AutoplaySlider
play={true}
cancelOnInteraction={true}
interval={0}
onTransitionStart={slide => setCurrent(slide.nextIndex)}
className="sliderHome"
>
{images.map((image, index) => {
let src = "/image/slider/portfolio/"+image.image;
//console.log(src);
return (
<div key={index} data-src={src}>
</div>
);
})}
</AutoplaySlider>
<GalleryCaption selected={current} title={title} description={description} area={slider}/>
</div>
)
};
export default StaticSlider;
描述生成器
const GalleryCaption = ({ selected = 0, title = [], description= [], area = 0 }) => {
const formattedIndex = selected + 1;
var title = title[selected];
var data = description[selected];
return (
<div className="containerDivDescriptionPortflio">
<div className="DivDescriptionPortflio">
<p id ={"description_portfolio_"+area} className="paragDescriptionPortflio" >
<h4>{title}</h4>
<hr></hr>
{
data.map((val) => (
<div className="rowDescriptionPortfolio">
<div className="divIndexPortfolio" dangerouslySetInnerHTML={{ __html: val.index }} >
</div>
<div className="divTextPortfolio" dangerouslySetInnerHTML={{ __html: val.text }} >
</div>
</div>
))}
</p>
</div>
</div>
);
};
export default GalleryCaption;
对象示例
{
"title":"text",
"data":[
{
"index":"text",
"text": "text"
},
{
"index":"text",
"text": "text"
}
],
"image": "folder/image.jpg"
},
(这是该类对象数组的一个元素)
现在的主要问题是,如果在使用效果中,我只调用 setTitle 函数,一切都会正常工作,但如果我也使用 setDescription,一切都会停止工作。我没有收到特定错误,但出现白屏。
我得到的错误
Warning: Each child in a list should have a unique "key" prop.
Check the render method of `PortfolioArea`. See https://reactjs.org/link/warning-keys for more information.
at div
at PortfolioArea (http://localhost:3000/static/js/bundle.js:1618:5)
at http://localhost:3000/static/js/bundle.js:4509:78
at Routes (http://localhost:3000/static/js/bundle.js:177110:5)
at Router (http://localhost:3000/static/js/bundle.js:177043:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:176523:5)
at App
at AppProvider (http://localhost:3000/static/js/bundle.js:3289:5)
Warning: Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://reactjs.org/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state
Please update the following components: AwesomeSlider
The above error occurred in the <GalleryCaption> component:
at GalleryCaption (http://localhost:3000/static/js/bundle.js:973:5)
at div
at StaticSlider (http://localhost:3000/static/js/bundle.js:3049:5)
at div
at PortfolioArea (http://localhost:3000/static/js/bundle.js:1618:5)
at http://localhost:3000/static/js/bundle.js:4510:78
at Routes (http://localhost:3000/static/js/bundle.js:177111:5)
at Router (http://localhost:3000/static/js/bundle.js:177044:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:176524:5)
at App
at AppProvider (http://localhost:3000/static/js/bundle.js:3290:5)
考虑向树中添加错误边界以自定义错误处理行为。
访问 https://reactjs.org/link/error-boundaries 以了解有关错误边界的更多信息。`
我尝试将 useEffect 的第二个参数更改为 null 并且还为每个参数使用唯一状态,但问题似乎是每次我尝试使用 useEffect 中的对象设置状态时,在第一次渲染时,我总是在该状态中得到一个空值。
有什么建议吗?
我认为在StaticSlider
中,由于images
和length
是根据slider
prop计算的,我建议使用useMemo()
来计算它们slider
更改,而不是将值重新分配给 var
变量,这在 React 中不应该这样做,并且会引发错误。
const StaticSlider = ({slider}) => {
const images = useMemo(
() => {
// calculate and return images value
// with `switch`
switch (slider) {
// ...
default:
return [];
}
},
[slider]
);
const length = useMemo(
() => {
// calculate and return length value
// with `switch`
switch (slider) {
// ...
default:
return 0;
}
},
[slider]
);
请注意,您当前的 switch
块没有 default
案例,您应该考虑返回一个带有 images
和 length
初始值的默认案例。
另请注意,images
的初始赋值是 images = ""
,这将使它成为 string
,但在 setDescription()
中,您调用的是 images.map()
是一个数组方法,所以当 images
是一个空字符串时,它不会在组件的 初始渲染 上工作。我认为这就是导致错误的原因。
images = []
or default: return []
for images inside switch
statement 应该更好。
最后,我认为您可以考虑在 useEffect()
中使用条件检查,仅在 title
和 description
上使用 setState
,当 images
已经填充时(有长度)。
useEffect(
() => {
if (images.length) {
setTitle(
images.map(
(slide) => (slide.title)
)
);
setDescription(
images.map(
(desc) => (desc.data)
)
);
}
},
[images]
);
我正在构建一个使用 React Awesome Slider 的 ReactJS 组件。 我要创建的是一个滑块,下面有一个描述 div,它会更改文本,然后我更改幻灯片。
现在,我找到了让它工作的方法,但我对对象的 setState 有疑问,这是代码。
滑块:
const AutoplaySlider = withAutoplay(AwesomeSlider);
const StaticSlider = ({slider}) => {
var images = "";
var length=0;
const [current, setCurrent] = useState(0);
const [title, setTitle] = useState([]);
const [description, setDescription] = useState([]);
switch (slider) {
case 'portfolio_sviluppo_software':
images = portfolio_description.sviluppo_software;
length= portfolio_description.sviluppo_software.length;
break;
case 'portfolio_domotica':
images = portfolio_description.domotica;
length= portfolio_description.domotica.length;
break;
case 'portfolio_digital_signage':
images = portfolio_description.digital_signage;
length= portfolio_description.digital_signage.length;
break;
case 'portfolio_ricerca_e_sviluppo':
images = portfolio_description.ricerca_e_sviluppo;
length= portfolio_description.ricerca_e_sviluppo.length;
break;
}
useEffect(
() => {
setTitle(
images.map(
(slide) => (slide.title)
)
);
setDescription(
images.map(
(desc) => (desc.data)
)
);
}, [images]
);
return(
<div>
<AutoplaySlider
play={true}
cancelOnInteraction={true}
interval={0}
onTransitionStart={slide => setCurrent(slide.nextIndex)}
className="sliderHome"
>
{images.map((image, index) => {
let src = "/image/slider/portfolio/"+image.image;
//console.log(src);
return (
<div key={index} data-src={src}>
</div>
);
})}
</AutoplaySlider>
<GalleryCaption selected={current} title={title} description={description} area={slider}/>
</div>
)
};
export default StaticSlider;
描述生成器
const GalleryCaption = ({ selected = 0, title = [], description= [], area = 0 }) => {
const formattedIndex = selected + 1;
var title = title[selected];
var data = description[selected];
return (
<div className="containerDivDescriptionPortflio">
<div className="DivDescriptionPortflio">
<p id ={"description_portfolio_"+area} className="paragDescriptionPortflio" >
<h4>{title}</h4>
<hr></hr>
{
data.map((val) => (
<div className="rowDescriptionPortfolio">
<div className="divIndexPortfolio" dangerouslySetInnerHTML={{ __html: val.index }} >
</div>
<div className="divTextPortfolio" dangerouslySetInnerHTML={{ __html: val.text }} >
</div>
</div>
))}
</p>
</div>
</div>
);
};
export default GalleryCaption;
对象示例
{
"title":"text",
"data":[
{
"index":"text",
"text": "text"
},
{
"index":"text",
"text": "text"
}
],
"image": "folder/image.jpg"
},
(这是该类对象数组的一个元素) 现在的主要问题是,如果在使用效果中,我只调用 setTitle 函数,一切都会正常工作,但如果我也使用 setDescription,一切都会停止工作。我没有收到特定错误,但出现白屏。
我得到的错误
Warning: Each child in a list should have a unique "key" prop.
Check the render method of `PortfolioArea`. See https://reactjs.org/link/warning-keys for more information.
at div
at PortfolioArea (http://localhost:3000/static/js/bundle.js:1618:5)
at http://localhost:3000/static/js/bundle.js:4509:78
at Routes (http://localhost:3000/static/js/bundle.js:177110:5)
at Router (http://localhost:3000/static/js/bundle.js:177043:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:176523:5)
at App
at AppProvider (http://localhost:3000/static/js/bundle.js:3289:5)
Warning: Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://reactjs.org/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state
Please update the following components: AwesomeSlider
The above error occurred in the <GalleryCaption> component:
at GalleryCaption (http://localhost:3000/static/js/bundle.js:973:5)
at div
at StaticSlider (http://localhost:3000/static/js/bundle.js:3049:5)
at div
at PortfolioArea (http://localhost:3000/static/js/bundle.js:1618:5)
at http://localhost:3000/static/js/bundle.js:4510:78
at Routes (http://localhost:3000/static/js/bundle.js:177111:5)
at Router (http://localhost:3000/static/js/bundle.js:177044:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:176524:5)
at App
at AppProvider (http://localhost:3000/static/js/bundle.js:3290:5)
考虑向树中添加错误边界以自定义错误处理行为。 访问 https://reactjs.org/link/error-boundaries 以了解有关错误边界的更多信息。`
我尝试将 useEffect 的第二个参数更改为 null 并且还为每个参数使用唯一状态,但问题似乎是每次我尝试使用 useEffect 中的对象设置状态时,在第一次渲染时,我总是在该状态中得到一个空值。
有什么建议吗?
我认为在StaticSlider
中,由于images
和length
是根据slider
prop计算的,我建议使用useMemo()
来计算它们slider
更改,而不是将值重新分配给 var
变量,这在 React 中不应该这样做,并且会引发错误。
const StaticSlider = ({slider}) => {
const images = useMemo(
() => {
// calculate and return images value
// with `switch`
switch (slider) {
// ...
default:
return [];
}
},
[slider]
);
const length = useMemo(
() => {
// calculate and return length value
// with `switch`
switch (slider) {
// ...
default:
return 0;
}
},
[slider]
);
请注意,您当前的 switch
块没有 default
案例,您应该考虑返回一个带有 images
和 length
初始值的默认案例。
另请注意,images
的初始赋值是 images = ""
,这将使它成为 string
,但在 setDescription()
中,您调用的是 images.map()
是一个数组方法,所以当 images
是一个空字符串时,它不会在组件的 初始渲染 上工作。我认为这就是导致错误的原因。
images = []
or default: return []
for images inside switch
statement 应该更好。
最后,我认为您可以考虑在 useEffect()
中使用条件检查,仅在 title
和 description
上使用 setState
,当 images
已经填充时(有长度)。
useEffect(
() => {
if (images.length) {
setTitle(
images.map(
(slide) => (slide.title)
)
);
setDescription(
images.map(
(desc) => (desc.data)
)
);
}
},
[images]
);