Поднятие состояния через несколько дочерних элементов

Немного застрял на этом. У меня есть родительский компонент Main, который переходит в компонент поиска, который затем переходит в компонент Select. Поиск запрашивает город, а затем обращается к API и возвращает 5 результатов поиска, и я отправляю их в компонент выбора, где сопоставляю результаты с формой выбора. Как только пользователь выбирает город и отправляет его, мне нужно, чтобы выбор был сохранен где-то в основном файле, чтобы я мог использовать его для других детей. Любая помощь приветствуется, я все еще разбираюсь в React.

Я попробовал сделать компонент Select прямым дочерним элементом основного, но мне это не понравилось. Я пытался отправить «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 handleChangeEvent = (event) => {
        setSearchTerm(event.target.value);
    }

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решением было бы использовать React Context. Что такое контекст реагирования? В React это состояние, и оно функционирует как крючок useState. Большая разница в том, что при создании контекста его можно обернуть вокруг компонента или компонентов, и все эти компоненты будут иметь доступ к состоянию без необходимости передавать реквизиты вверх или вниз. Напишу небольшой пример, как это будет выглядеть:

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).

Будет ли это работать и для доступа к моему выбранному компоненту? На данный момент структура такая: Главное – Поиск – Выбрать. Select является дочерним элементом Search. Вы объявляете CityContext вне основной функции?

Adam 17.06.2024 00:00

Я получаю много ошибок при попытке использовать это.

Adam 17.06.2024 01:07

Я получаю подобные ошибки, как только помещаю новый код в свой основной раздел.

Adam 17.06.2024 04:19

Uncaught ReferenceError: экспорт не определен

Adam 17.06.2024 04:19

Uncaught TypeError: невозможно прочитать свойства неопределенного типа (чтение «useState»)

Adam 17.06.2024 04:19

Код не предназначен для копирования и вставки, он просто иллюстрирует, как он будет выглядеть в вашем коде. В опубликованном мною документе по ссылке есть рабочий пример, который вы можете использовать.

Davyd Shapovalov 17.06.2024 07:17

Да, поставщик, вокруг которого вы обертываете свои компоненты, может использоваться внутри всех компонентов, вокруг которых он заключен, а также его дочерних компонентов.

Davyd Shapovalov 17.06.2024 07:18

Если вы хотите, вы можете создать воспроизводимый пример со своим кодом внутри песочницы или чего-то еще, и я могу показать, как использовать контекст, и объяснить это.

Davyd Shapovalov 17.06.2024 07:28

Было бы здорово, постараюсь как можно скорее что-нибудь собрать

Adam 17.06.2024 07:30

Эта ссылка должна работать, все находится в папке «раздел A», и я включил корневой HTML-файл codeandbox.io/p/live/8d22195b-d51b-447a-aafa-2eb53d89a662

Adam 17.06.2024 07:42

Да, дай мне немного времени

Davyd Shapovalov 17.06.2024 07:47

Я ценю это, большое спасибо

Adam 17.06.2024 07:53

Я обновил песочницу кода. Я не уверен, как это проверить, потому что все это находится в отдельной папке, которая не используется. Но я уверен, что именно так и должно работать. Если это не работает, я добавлю минимальный пример в папку «src», чтобы показать вам. Надеюсь, это поможет!

Davyd Shapovalov 17.06.2024 07:58

Эй, я думаю, что это начинает работать, но как только я помещаю строку импорта вверху, у меня появляется ошибка

Adam 17.06.2024 18:49

Uncaught ReferenceError: требование не определено

Adam 17.06.2024 18:49

Вы импортируете его через require? Я думаю, это не сработает, вам придется использовать import {...} from "react";

Davyd Shapovalov 17.06.2024 18:51

И когда я добавляю его в компонент поиска, я получаю ту же ошибку плюс

Adam 17.06.2024 18:55

Uncaught ReferenceError: createContext не определен

Adam 17.06.2024 18:56

я не уверен, что именно требуется, но я только что скопировал тег импорта, который у вас есть в коде песочницы, и, похоже, он ему не нравится

Adam 17.06.2024 18:56

Давайте продолжим обсуждение в чате.

Adam 17.06.2024 19:12

Другие вопросы по теме