reactjs 我想使用属性将数据从子组件传递到父组件

deyfvvtc  于 2023-01-30  发布在  React
关注(0)|答案(3)|浏览(173)

我尝试使用子组件TagsInput.js中的props将数据传递给父组件Top.js,在子组件TagsInput.js中,我可以添加标记,但我不明白是什么导致了错误...
我想要达到的目标
我想将"tags"从具有props的子组件中的TagsInput.js传递给父组件Top.js。
我得到了这样的错误

props.setTagsinput is not a function

TagsInput.js

import React from "react";

const TagsInput = (props) => {

    //1, Define the tags variable to store the entered tags. (I want to pass the value of the tags variable to the parent component Top.js)
    const [tags, setTags] = React.useState([]);

    //2, Put formText in the function received from the parent component and return it.
    props.setTagsinput(tags);
    console.log(props)

    let tag_list = []
    tag_list.push(tags);

    const addTags = event => {
      if (event.key === "Enter" && event.target.value !== "") {
          setTags([...tags, event.target.value]);
          event.target.value = "";
      }
    };
    const removeTags = index => {
      setTags([...tags.filter(tag => tags.indexOf(tag) !== index)]);
    };

    return (
        <div className="tags-input">
            <div className="tags_section">
                {tags.map((tag, index) => (
                    <div className="tag tag-flex" key={index}>
                            <p className="tag-p">{tag}</p>
                    </div>
                ))}
            </div>
            <input
                type="text"
                onKeyUp={event => addTags(event)}
                placeholder="Press enter to add tags"
            />
        </div>
    );
};
export default TagsInput;

Top.js

import React, {useState, useEffect} from 'react';
import axios from 'axios';
import Student from './Student';
import TagsInput from "./TagsInput";

const Top = () => {
  const [ posts, setPosts] = useState([]);
  const [ allPosts, setAllPosts] = useState([]);

  let tag_list = []
  const [searchKeyword, setSearchKeyword] = React.useState("");
  const [searchTagKeyword, setTagSearchKeyword] = React.useState("");
  console.log(searchKeyword)

  const[tags_from_tagsinput, setTagsinput]= useState("");
  console.log(tags_from_tagsinput);

  useEffect(() => {
    axios.get('xxx.com')
    .then(result => {
      setPosts(result.data.students);
      setAllPosts(result.data.students);
      if (searchKeyword) {
        getSearchResult()
      }
    })},
    [searchKeyword]);


  const getSearchResult = () => {
    console.log(searchKeyword)
    const result = allPosts.filter((output, index) => {
      return output.firstName.toLowerCase().includes(searchKeyword.toLowerCase())||output.lastName.toLowerCase().includes(searchKeyword.toLowerCase());
    });
    console.log(result)
    setPosts(result);
  };

  
  const getTagSearchResult = () => {
    console.log(searchTagKeyword)
    const result = allPosts.filter((output, index) => {
      return output.lastName.toLowerCase().includes(searchTagKeyword.toLowerCase());
    });
    console.log(result)
    setPosts(result);
  };

  return (
    <div>
      <TagsInput setTagsinput={setTagsinput}/>
      <div>
      <input className="search-box" placeholder="" value={searchKeyword} onChange={(e) => setSearchKeyword(e.target.value)}/>
      </div>
      <div>
      <input className="search-box" placeholder="" value={searchTagKeyword} onChange={(e) => setSearchKeyword(e.target.value)}/>
      </div>
      <div>
      {searchKeyword &&
      <p>{searchKeyword} Search</p>
      }
      {posts ?
      <>
        {posts.map((data, i) =>
          <Student data={data} />
        )}
      </>
      :
      <div>
        <p>Not Found!</p>
      </div>
      }
      </div>
    </div>
  );
}
export default Top;

Student.js

import React, {useState} from 'react';
import TagsInput from './TagsInput';

const Student = (props) => {
const [show, setShow] = useState(false)

  const gradesAverage = (grades) => {
    let sum = 0;
    grades.forEach(function(score) {
      sum += Number(score);
    });
    let ave = sum / grades.length
    return ave;
  };

  return (
    <div className="flex">
        <div className="image">
            <img src={props.data.pic} className="profile" />
        </div>
        <div>
            <p className="name">{props.data.firstName} {props.data.lastName}</p>
            <button className="button" onClick={() => setShow(!show)}>
                {show? <div className="button_p">-</div>:<div className="button_p">+</div>}
            </button>
            <div className="info">
                <p>Email: {props.data.email}</p>
                <p>Company: {props.data.company}</p>
                <p>Skill: {props.data.skill}</p>
                <p>Average Grade: {gradesAverage(props.data.grades)}%</p>
                {show &&
                    <>
                        <p>Test 1: {props.data.grades[0]}%</p>
                        <p>Test 2: {props.data.grades[1]}%</p>
                        <p>Test 3: {props.data.grades[2]}%</p>
                        <p>Test 4: {props.data.grades[3]}%</p>
                        <p>Test 5: {props.data.grades[4]}%</p>
                        <p>Test 6: {props.data.grades[5]}%</p>
                        <p>Test 7: {props.data.grades[6]}%</p>
                        <p>Test 8: {props.data.grades[7]}%</p>
                    </>
                }
                <TagsInput />
            </div>
        </div>
    </div>
  );
}
export default Student;
kpbwa7wx

kpbwa7wx1#

你不能直接在另一个组件中使用一个组件的钩子声明,你需要有一个回调函数来更新那个状态。我修改了你的代码,在student标记input中使用了首页setTagsinput
Top.js

import React, { useState, useEffect } from "react";
import axios from "axios";
import Student from "./Student";
import TagsInput from "./TagsInput";

const Top = () => {
  const [posts, setPosts] = useState([]);
  const [allPosts, setAllPosts] = useState([]);

  let tag_list = [];
  const [searchKeyword, setSearchKeyword] = React.useState("");
  const [searchTagKeyword, setTagSearchKeyword] = React.useState("");
  console.log(searchKeyword);

  const [tags_from_tagsinput, setTagsinput] = useState("");
  console.log(tags_from_tagsinput);

  useEffect(() => {
    axios.get("xxx.com").then((result) => {
      setPosts(result.data.students);
      setAllPosts(result.data.students);
      if (searchKeyword) {
        getSearchResult();
      }
    });
  }, [searchKeyword]);

  const getSearchResult = () => {
    console.log(searchKeyword);
    const result = allPosts.filter((output, index) => {
      return (
        output.firstName.toLowerCase().includes(searchKeyword.toLowerCase()) ||
        output.lastName.toLowerCase().includes(searchKeyword.toLowerCase())
      );
    });
    console.log(result);
    setPosts(result);
  };

  const getTagSearchResult = () => {
    console.log(searchTagKeyword);
    const result = allPosts.filter((output, index) => {
      return output.lastName
        .toLowerCase()
        .includes(searchTagKeyword.toLowerCase());
    });
    console.log(result);
    setPosts(result);
  };

  const setTagsFromStudent = (tags) => {
    setTagsinput(tags);
  };

  return (
    <div>
      <div>
        <input
          className="search-box"
          placeholder=""
          value={searchKeyword}
          onChange={(e) => setSearchKeyword(e.target.value)}
        />
      </div>
      <div>
        <input
          className="search-box"
          placeholder=""
          value={searchTagKeyword}
          onChange={(e) => setSearchKeyword(e.target.value)}
        />
      </div>
      <div>
        {searchKeyword && <p>{searchKeyword} Search</p>}
        {posts ? (
          <>
            {posts.map((data, i) => (
              <Student data={data} setStudentTags={setTagsFromStudent} />
            ))}
          </>
        ) : (
          <div>
            <p>Not Found!</p>
          </div>
        )}
      </div>
    </div>
  );
};
export default Top;

Student.js

import React, { useState } from "react";
import TagsInput from "./TagsInput";

const Student = (props) => {
  const [show, setShow] = useState(false);

  const gradesAverage = (grades) => {
    let sum = 0;
    grades.forEach(function (score) {
      sum += Number(score);
    });
    let ave = sum / grades.length;
    return ave;
  };

  return (
    <div className="flex">
      <div className="image">
        <img src={props.data.pic} className="profile" />
      </div>
      <div>
        <p className="name">
          {props.data.firstName} {props.data.lastName}
        </p>
        <button className="button" onClick={() => setShow(!show)}>
          {show ? (
            <div className="button_p">-</div>
          ) : (
            <div className="button_p">+</div>
          )}
        </button>
        <div className="info">
          <p>Email: {props.data.email}</p>
          <p>Company: {props.data.company}</p>
          <p>Skill: {props.data.skill}</p>
          <p>Average Grade: {gradesAverage(props.data.grades)}%</p>
          {show && (
            <>
              <p>Test 1: {props.data.grades[0]}%</p>
              <p>Test 2: {props.data.grades[1]}%</p>
              <p>Test 3: {props.data.grades[2]}%</p>
              <p>Test 4: {props.data.grades[3]}%</p>
              <p>Test 5: {props.data.grades[4]}%</p>
              <p>Test 6: {props.data.grades[5]}%</p>
              <p>Test 7: {props.data.grades[6]}%</p>
              <p>Test 8: {props.data.grades[7]}%</p>
            </>
          )}
          {/*pass settag from topTag component*/}
          <TagsInput setStudentTags={props.setStudentTags} />
        </div>
      </div>
    </div>
  );
};
export default Student;

TagsInput.js

import React from "react";

const TagsInput = (props) => {
  const [tags, setTags] = React.useState([]);

  let tag_list = [];
  tag_list.push(tags);

  const addTags = (event) => {
    if (event.key === "Enter" && event.target.value !== "") {
      setTags([...tags, event.target.value]);
      // call function pass down from toptag
      props.setStudentTags(tags);
      event.target.value = "";
    }
  };
  const removeTags = (index) => {
    setTags([...tags.filter((tag) => tags.indexOf(tag) !== index)]);
  };

  return (
    <div className="tags-input">
      <div className="tags_section">
        {tags.map((tag, index) => (
          <div className="tag tag-flex" key={index}>
            <p className="tag-p">{tag}</p>
          </div>
        ))}
      </div>
      <input
        type="text"
        onKeyUp={(event) => addTags(event)}
        placeholder="Press enter to add tags"
      />
    </div>
  );
};
export default TagsInput;
zlwx9yxi

zlwx9yxi2#

您应该考虑探索React上下文-https://reactjs.org/docs/context.html,它正是为类似的内容而构建的。
您得到这个错误是因为,正如您提到的,TagsInput组件在Student组件中使用,但它没有将状态设置器setTagsInput函数传递给TagsInput组件。现在,假设您需要在Student中创建标签并在Top中显示,还假设两者都呈现在同一个父组件中,你可以在父组件中为标签创建一个状态。这个组件会传递一个状态setter函数给StudentStudent传递setter给TagsInput,状态本身传递给Top以使用标签列表。类似于:

const App = () => {
    const [tags,setTags] = useState([]);
    return (<div>
        <Top tags={tags} />
        <Student setTags={setTags} />
    </div>);
}

然后,您的Student组件可以将其传递给TagsInput,如下所示:

const Student = (props) => {
   return (<div>
   {/* everything else */}
   <TagsInput setTagsinput={props.setTags} />
   </div>)
}
vdzxcuhz

vdzxcuhz3#

在Top component中,您可以创建一个函数来更新tags_from_tagsinput钩子,然后将其作为props传递给子component

import TagsInput from "./TagsInput";
const Top = () => {

  const[tags_from_tagsinput, setTagsinput]= useState("");
  console.log(tags_from_tagsinput);

  const getTag = (value) => {
    setTagsinput(value);
  };

  return (
    <div>
      <TagsInput  getTag={getTag} />
    </div>
  );
}
export default Top;

现在,您可以从TagsInput component调用此函数来更新Top的tags_from_tagsinput,假设您希望在用户单击按钮时进行更新

import React from "react";

const TagsInput = (props) => {

    return (
        <div className="tags-input">
         ...
        <button onClick={()=>{props.getTag(tags)}}>updated parent component</button>
        </div>
    );
};
export default TagsInput;

相关问题