通过多个子元素提升状态

问题描述 投票:0回答:1

有点卡在这个上了。我有一个主要父组件,它转到搜索组件,然后转到选择组件。搜索请求一个城市,然后转到 API 并返回 5 个搜索结果,我将它们发送到选择组件,在其中将结果映射到选择表单中。一旦用户选择城市并提交,我需要将选择存储在主目录中的某个位置,以便我可以在其他孩子身上使用它。感谢任何帮助,仍然可以掌握 React。

我尝试过让 Select 组件成为 main 的直接子组件,但它不喜欢那样。 我尝试过将“cityObj”通过搜索发送到选择中,但没有成功,除非我做错了什么。 我虽然可能会将需要信息的“主体”组件作为“选择”的子组件,但我仍在努力。

Main.js

function Main() {
    const [cityObj, setCityObj] = React.useState('');
    return (
        <div className="container p-5 bg-primary">
            <i className='text-danger fw-bold'>Main component</i>
            <h2 className='m-3'>My React Weather Application</h2>
            <Search />
            <hr />
            <Body />
        </div>
    );
}

搜索.js

function Search(props) {
    const [searchTerm, setSearchTerm] = React.useState('');
    const [cityArray, setCityArray] = React.useState([]);
    const [cel, setCel] = React.useState(null);
    const [selectedCity, setSelectedCity] = React.useState(null);
    

    const Weather_API_key = '55c5392db030dbb75249aa1ff9b8a871';
    const url = 'http://api.openweathermap.org/geo/1.0/direct';
    

    const handleChange = (event) => {
        setSearchTerm(event.target.value);
    }

    const handleSubmit = (event) => {
        console.log('The form submitted with input: ' + searchTerm);
        setCel(() => (searchTerm - 32) / 1.8);
        event.preventDefault(); // Prevent default form submission behavior 
        console.log(searchTerm);
        fetch(`${url}?q=${searchTerm}&limit=5&appid=${Weather_API_key}&units=metric`)
            .then(response => response.json())
            .then(data => {
                console.log(data);
                setCityArray(data);
                console.log('API data came mounted');
            });
    }

    return (
        <div className="container p-3 bg-success">
            <i className='text-danger fw-bold'>Search component</i>
            <form onSubmit={handleSubmit} className='my-3 row g-3'>
                <label className="col-sm-4 col-form-label">
                    Please enter city name:
                </label>
                <div className="col-sm-4">
                    <input type="text" value={searchTerm}
                        onChange={handleChange} className="form-control" />
                </div>
                <div className="col-sm-4">
                    <input type="submit" value="Search" className="btn btn-primary mb-3" />
                </div>
            </form>
            <Select cityArray={cityArray} />
        </div>
    );
}

选择.js

function Select(props) {
    const [userInput, setUserInput] = React.useState('');
    const [selectedValue, setSelectedValue] = React.useState(null);

    const handleChange = (event) => {
        // Get the input from the user and save it in a state variable
        // event.target is the input element
        setUserInput(event.target.value);
    }

    const handleSubmit = (event) => {
        console.log('The form submitted with input: ' + userInput);
        setSelectedValue(() => userInput);
        event.preventDefault(); // Prevent default form submission behavior 
    }
    return (
        <div className="container p-3 bg-warning">
            <i className='text-danger fw-bold'>Select component</i>
            <form onSubmit={handleSubmit} className=' row g-3'>
                <label className="col-sm col-form-label">
                    Choose your country:</label>
                <select value={userInput} onChange={handleChange}
                    className='form-select col-md'>
                   {props.cityArray.map((city, index) =>
                        <option key={city.name + index} value={`${city.name} , ${city.country}`}>
                            {city.name}, {city.country}</option>
                    )}
                </select>
                <div className="col-sm col-form-label">
                    <input type="submit" value="Submit" className="btn btn-primary mb-3" />
                </div>
            </form>

            {
                selectedValue &&
                <div> You selected {selectedValue} </div>
            }
        </div>
    );
}

reactjs state
1个回答
0
投票

解决方案是使用

React Context
。什么是反应上下文?它是 React 中的一种状态,其功能类似于
useState
钩子。最大的区别是,在创建上下文时,它可以包裹在一个或多个组件周围,并且所有这些组件都可以访问状态,而不需要向上或向下传递 props。我会写一个简短的例子,它会是什么样子:

Main.js

import { createContext, useState } from 'react';

const CityContext = createContext();

export function Main() {
  const [cityObj, setCityObj] = useState();

  return (
    <CityContext.Provider value={{ cityObj, setCityObj }}>
      <Search />
      <Body />
    </CityContext.Provider>
  );
}

在上面的代码中,我们使用

createContext
钩子创建了一个上下文,并将其包裹在我们的
Search
Body
组件周围。现在,上下文提供程序内的所有组件都可以访问
cityObj
setCityObj
。我们如何使用和改变上下文?

Search.js

  let { cityObj, setCityObj } = useContext(CityContext);

  const changeCityState = () => {
    setCityObj({exampleObj: "example"});
  }

  return (
    <div>
      {cityObj}
    </div>
  );

在上面的代码中,我们使用

useContext
钩子并将 CityContext 作为参数传递以访问上下文提供者的
value
。现在我们可以像“正常”状态一样使用上下文。如果更改状态,则使用状态的每个组件都将重新渲染!我建议阅读更多内容(https://react.dev/reference/react/createContext)。

© www.soinside.com 2019 - 2024. All rights reserved.