У меня есть react-App
с редуксом, использующим react-hooks
функциональные компоненты, он правильно отображает список наставников в дочернем компоненте. я добавил в него окно поиска и функцию handlchange
для обновления компонента списка (дочерний компонент). функция handlechange
работает нормально и назначает переменную newlist
в filtered
внутри тела handlechange function
, однако значение filtered
вне функции handlechange
остается неизменным, поэтому обновленная отфильтрованная переменная не назначена TutorList Component
.
Компонент Tutors.jsx
выглядит следующим образом:
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from 'react-redux';
import { Link, useParams, useHistory } from 'react-router-dom';
import TutorList from "./TutorList";
import * as actions from "../_actions/tutorActions";
import { TextField, Button, FormControl, } from "@material-ui/core";
const initialFieldValues = {
search: ""
}
const Tutors = (props) => {
const [values, setValues] = useState(initialFieldValues)
let history = useHistory()
const dispatch = useDispatch();
// getting of tutorlist
let tutor = useSelector(state => state.tutor.list);
// sorting of tutors on date
let tutorList = tutor.sort((a, b) => b.updatedOn.localeCompare(a.updatedOn));
useEffect(() => {
dispatch(actions.fetchAll())
}, [])
console.info("tutorList:", tutorList)
// Variable to hold the filtered list before putting into state
let newList = [];
let filtered = tutorList;
//when filter changes from '' to something filtered should be updated with newlist
function handleChangeEvent(e) {
const { name, value } = e.target
const fieldValue = { [name]: value }
setValues({
...values,
...fieldValue
})
// If the search bar isn't empty
if (values.search !== "") {
// Use .filter() to determine which items should be displayed
// based on the search terms
newList = tutorList.filter(item => {
// change current item to lowercase
const lc = item.fullName.toLowerCase();
// change search term to lowercase
const filter = e.target.value.toLowerCase();
console.info("filter", filter);
// check to see if the current list item includes the search term
// If it does, it will be added to newList. Using lowercase eliminates
// issues with capitalization in search terms and search content
return lc.includes(filter);
});
} else {
newList = tutorList;
}
console.info("newList:", newList)//shows correct list
filtered = newList
console.info("filtered:", filtered)//shows correct value
}
return (
<div>
<br />
<TextField
name = "search"
variant = "outlined"
label = "Search Tutor"
paceholder = "search tutor..."
value = {values.search}
onChange = {handleChangeEvent}
/>
<TutorList
tutorList = {filtered}
/>
<Button onClick = {() => history.goBack()}
size = "small" variant = "contained" color = "secondary">
back
</Button>
</div>
);
}
export default Tutors;
Компонент TutorList
должен отображать новый список на основе фильтра, введенного в поле поиска. кто-нибудь поможет найти обходной путь или лучшее решение. Заранее спасибо.
создать новое состояние для
const Tutors =(props)=> {
const [values, setValues] = useState(initialFieldValues)
const [filtered, setFiltered] = useState(null)
внутри функции handleChangeEvent()
задайте filtered
значение отфильтрованного элемента:
function handleChangeEvent(e){
//........
console.info("newList:",newList)//shows correct list
//filtered=newList <= instead of this
setFiltered(newList) // <= do this
console.info("filtered:",filtered)//shows correct value
}
Окончательный код должен выглядеть так:
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link, useParams, useHistory } from "react-router-dom";
import TutorList from "./TutorList";
import * as actions from "../_actions/tutorActions";
import { TextField, Button, FormControl } from "@material-ui/core";
const initialFieldValues = {
search: "",
};
const Tutors = (props) => {
const [values, setValues] = useState(initialFieldValues);
const [filtered, setFiltered] = useState(null);
let history = useHistory();
const dispatch = useDispatch();
// getting of tutorlist
let tutor = useSelector((state) => state.tutor.list);
// sorting of tutors on date
let tutorList = tutor.sort((a, b) => b.updatedOn.localeCompare(a.updatedOn));
useEffect(() => {
dispatch(actions.fetchAll());
}, []);
console.info("tutorList:", tutorList);
// Variable to hold the filtered list before putting into state
let newList = [];
let filtered = tutorList;
//when filter changes from '' to something filtered should be updated with newlist
function handleChangeEvent(e) {
const { name, value } = e.target;
const fieldValue = { [name]: value };
setValues({
...values,
...fieldValue,
});
// If the search bar isn't empty
if (values.search !== "") {
// Use .filter() to determine which items should be displayed
// based on the search terms
newList = tutorList.filter((item) => {
// change current item to lowercase
const lc = item.fullName.toLowerCase();
// change search term to lowercase
const filter = e.target.value.toLowerCase();
console.info("filter", filter);
// check to see if the current list item includes the search term
// If it does, it will be added to newList. Using lowercase eliminates
// issues with capitalization in search terms and search content
return lc.includes(filter);
});
} else {
newList = tutorList;
}
console.info("newList:", newList); //shows correct list
setFiltered(newList); // update filtered state
console.info("filtered:", filtered); //shows correct value
}
return (
<div>
<br />
<TextField
name = "search"
variant = "outlined"
label = "Search Tutor"
paceholder = "search tutor..."
value = {values.search}
onChange = {handleChangeEvent}
/>
{filtered && <TutorList tutorList = {filtered} />}
<Button
onClick = {() => history.goBack()}
size = "small"
variant = "contained"
color = "secondary"
>
back
</Button>
</div>
);
};
export default Tutors;
просто используйте условный рендеринг. {filtered && <TutorList tutorList = {filtered} />}
Нет необходимости обновлять newList, отфильтрованный из handleChangeEvent. React так не работает. У вас не будет ререндера. Единственное, что вы должны сделать в своем handleChangeEvent, это установить значение
const [textInputValue, setTextInputValue] = useState('');
function handleChangeEvent(e) {
setTextInputValue(e.target.value);
}
затем выполните всю сортировку на основе
let tutor = useSelector(state => state.tutor.list)
// and textInputValue
Также нет необходимости хранить отфильтрованные значения в состоянии.
Спасибо за помощь. Я пробовал это, так как я использовал разбиение на страницы в tutorList, это не работает из-за неопределенной длины null. Если я использую массив [] вместо null в
const [filtered, setFiltered] = useState(null);
, он не отображается в первый раз. он показывает пустой список.