一个下拉菜单会影响另一个下拉菜单

时间:2020-07-24 01:23:02

标签: javascript reactjs

我和我的朋友正在开发一个使用Lexicala API的React转换器应用程序。我们有两个选择器组件:一个用于源语言,一个用于目标语言。用户将首先选择源语言,然后根据他们选择的内容,在第二个下拉菜单中填充可用目标语言列表。有人对我们如何使源语言选择器组件中的状态更新影响第二个组件有任何建议吗?

我包括了每个组件的代码(不带注释)。如果您认为我们已经做错了某些事情,请告诉我。

SourceLanguageSelector.js

import React, {useState, useEffect} from 'react';
import { encode } from "base-64";

let headers = new Headers();

headers.append('Authorization', 'Basic ' + encode(process.env.REACT_APP_API_USERNAME + ":" + process.env.REACT_APP_API_PASSWORD));

const SourceLanguageSelector = () => {

    const [loading, setLoading] = useState(true);

    const [items, setItems] = useState([
        { label: "Loading...", value: "" }
    ]);

    const [value, setValue] = useState();

    

    useEffect(() => {

   
        let unmounted = false;

        async function getLanguages() {

            
            const request = await fetch("https://dictapi.lexicala.com/languages", {
                        method: 'GET', headers: headers
                    });
            const body = await request.json();
            console.log(body);

            
            const sourceLang = body.resources.global.source_languages;
            const langName = body.language_names;

            const compare = (sourceLanguage, languageName) => {
                return sourceLanguage.reduce((obj, key) => {
                    if (key in languageName) {
                        obj[key] = languageName[key];
                    }
                    return obj;
                }, {});
            }

            const sourceLanguageNames = compare(sourceLang, langName);
            
           
            if (!unmounted) {
                setItems(
                    Object.values(sourceLanguageNames).map((sourceLanguageName) => ({
                        label: sourceLanguageName,
                        value: sourceLanguageName
                    }))
                    );
                setLoading(false);
            }
        }
        getLanguages();

   
        return () => {
            unmounted = true;
        }
    }, []);

    return (
        <select 
            disabled={loading}
            value={value}
            onChange={e => setValue(e.currentTarget.value)}>
            {items.map(item => (
                <option key={item.value} value={item.value}>
                    {item.label}
                </option>
            ))}
        </select>
    );

};

export default SourceLanguageSelector;

TargetLanguageSelector.js

import React, { useState, useEffect } from 'react';
import { encode } from 'base-64';

let headers = new Headers();

headers.append('Authorization', 'Basic ' + encode(process.env.REACT_APP_API_USERNAME + ":" + process.env.REACT_APP_API_PASSWORD));

const TargetLanguageSelector = () => {

    
    const [loading, setLoading] = useState(true);

    
    const [items, setItems] = useState([
        { label: "Loading...", value: "" }
    ]);

    
    const [value, setValue] = useState();


    useEffect(() => {

 
        let unmounted = false;

        async function getLanguages() {
            
            const request = await fetch("https://dictapi.lexicala.com/languages", {
                        method: 'GET', headers: headers
                    });
            const body = await request.json();
            console.log(body);


           const targetLang = body.resources.global.target_languages;
           const langName = body.language_names;

           const compare = (targetLanguage, languageName) => {
               return targetLanguage.reduce((obj, key) => {
                   if (key in languageName) {
                       obj[key] = languageName[key];
                   }
                   return obj;
               }, {});
           }

           const targetLanguageNames = compare(targetLang, langName);
            
            
            if (!unmounted) {
                setItems(
                    Object.values(targetLanguageNames).map(target_languages => 
                    ({
                        label: target_languages, 
                        value: target_languages
                    }))
                    );
                setLoading(false);
            }
        }
        getLanguages();

        
        return () => {
            unmounted = true;
        }
    }, []);

    return (
        <select 
            disabled={loading}
            value={value}
            onChange={e => setValue(e.currentTarget.value)}>
            {items.map(item => (
                <option key={item.value} value={item.value}>
                    {item.label}
                </option>
            ))}
        </select>
    );

};

export default TargetLanguageSelector;

2 个答案:

答案 0 :(得分:0)

您可以通过父级协调各个选择之间的状态。将回调函数传递给Source,该函数在其onChange处理函数触发时被调用,将所选语言传递给父级。在父级中,为当前选择的语言创建状态,并将其作为道具传递给Target。在target中,您可以在依赖项数组中有一个带有该道具的useEffect,因此无论何时Source中选定的语言发生变化,Target都会进行适当的api调用。

答案 1 :(得分:0)

您将具有三个选项,可以在两个单独的组件之间建立连接。

  1. 将父级作为两个子级之间的连接器。
e.g, Use a function props to trigger handler in parent. 
This handler will change the state of parent and it will lead to change the
props of another children like how @EvanMorrison has answered.
  1. 您可以使用全局状态树,即Redux,MobX或Flux之类的状态管理库,它将帮助您管理单个事实来源。因此,当您在一个组件中分派操作时,可以在另一个组件处检测到该状态,然后使用useEffect挂钩再次使用该状态作为依赖项来触发。

  2. 另一种模式是使用Context API,即使对我来说,尽管了解概念,但我很少使用它。

您可以找到更多的解释和示例here

https://reactjs.org/docs/context.html#updating-context-from-a-nested-component

React.js - Communicating between sibling components

相关问题