如何在不运行useEffect的情况下初始化状态两次

时间:2020-10-23 12:35:42

标签: reactjs react-hooks

我是新来的,在此玩具问题中,控制台中显示了所选省份或所选城市的人口。我正在尝试使用特定值初始化省份状态,但该值会被覆盖,因为useEffect在render上运行了两次,第一次是正确的总体输出,第二次是空数组,如何更改代码以防止这是真的吗?

import React, { Fragment,useEffect, useState } from "react";
import useDropdown from "./useDropdown";

const canada_json=[
    {
        "name" : "Alberta",
        "short" : "AB",
        "population" : 4067175,
        "capital" :"Edmonton",
        "capital_population" : 981280
        
    }
    ,
    {
        "name" : "British Columbia",
        "short" : "BC",        
        "population" : 4648055,
        "capital" : "Victoria",        
        "capital_population" : 92141 
    }] 

const Provincelist = () => {    
const [provinces, setprovinces] =useState([{value:{label: '', value : ""}}])

//Dropdown State I'm trying to initialise -  Defined as useDropdown(label, defaultState, options) 
const [province, ProvincesDropdown] = useDropdown("Provinces", "AB", provinces);

const [capitals, setcapitals] =useState([{value:{label: '', value : ""}}])    
const [capital, CapitalsDropdown, setcapital] = useDropdown("Capitals","", capitals);

//Populates Province Dropdown
useEffect(() =>{  
    const options = canada_json.map(d => ({
        "value" : d.short,
        "label" : d.name
      }))
      setprovinces(options)        
  },[]);

  //Populates Capital Dropdown after province selected and displays province population
  useEffect(() =>{ 
       
    const newlist = canada_json.filter(obj => obj.short === province) 
    const options = newlist.map(d => ({
        "value" : d.short,
        "label" : d.capital
      }))
      setcapitals(options) 
      
      const newlist2 = canada_json.filter(obj => obj.short === province).map((obj) => obj.population)     
      console.log(newlist2) 
  },[province]);
  
  //If Capital Dropdown changes display capital population
  useEffect(() =>{      
    const newlist = canada_json.filter(obj => obj.short === capital).map((obj) => obj.capital_population) 
    console.log(newlist)             
  },[capital]);      

  return (
    <Fragment>
    <ProvincesDropdown /> 
    <CapitalsDropdown />    
    </Fragment>
  )      
}
export default Provincelist;

这是useDropDown的代码

import React, { useState } from "react";

const useDropdown = (label, defaultState, options) => {
  const [state, updateState] = useState(defaultState);
  const id = `use-dropdown-${label.replace(" ", "").toLowerCase()}`;
  const Dropdown = () => (
    <label htmlFor={id}>
      {label}
      <select
        id={id}
        value={state}
        onChange={e => updateState(e.target.value)}        
        disabled={!options.length}
      >
        
        <option hidden>Please Select...</option>
        {options.map(item => (
          <option key={item.value} value={item.value}>
            {item.label}
          </option>
        ))}
      </select>
    </label>
  );
  return [state, Dropdown, updateState];
};

export default useDropdown;

2 个答案:

答案 0 :(得分:0)

如果省份永远不会更新,请将其保存在useRef

人口需要更新,因此我们将其保存在useState

import React, { Fragment, useEffect, useState, useRef } from "react";

const canada_json = [
  {
    name: "Alberta",
    short: "AB",
    population: 4067175,
    capital: "Edmonton",
    capital_population: 981280
  },
  {
    name: "British Columbia",
    short: "BC",
    population: 4648055,
    capital: "Victoria",
    capital_population: 92141
  }
];

const Provincelist = () => {
  const provinces = useRef(
    canada_json.map((d) => ({
      value: d.short,
      label: d.name
    }))
  );

  const [population, setpopulation] = useState("");

  //Dropdown State I'm trying to initialise -  Defined as useDropdown(label, defaultState, options)
  const [province, ProvincesDropdown] = useDropdown(
    "Provinces",
    "AB",
    provinces.current
  );

  const [capitals, setcapitals] = useState([
    { value: { label: "", value: "" } }
  ]);

  const [capital, CapitalsDropdown] = useDropdown("Capitals", "", capitals);

  //Populates Capital Dropdown after province selected and displays province population
  useEffect(() => {
    const newlist = canada_json.filter((obj) => obj.short === province);
    const options = newlist.map((d) => ({
      value: d.short,
      label: d.capital
    }));
    setcapitals(options);
  }, [province]);

  useEffect(() => {
    if (capital) {
      const newPopulation = canada_json.find(
        (province) => province.short === capital
      ).capital_population;
      setpopulation(newPopulation);
    }
  }, [capital]);

  return (
    <Fragment>
      <ProvincesDropdown />
      <CapitalsDropdown />
      <span>{population}</span>
    </Fragment>
  );
};

export default Provincelist;

答案 1 :(得分:0)

我注意到在您的.map的两个useEffect中,它返回的对象与{{1}的两个useState的初始值形状都不匹配}}和provinces

capitals

应更改为:

const [provinces, setprovinces] = useState([{value: {label: '', value: ''}}]);
useEffect(() =>{  
    const options = canada_json.map(d => ({
        "value" : d.short,
        "label" : d.name
      }))
    setprovinces(options);    
},[]);