#javascript #reactjs
#javascript #reactjs
Вопрос:
Я обнаружил странное поведение в своем коде react. Я довольно новичок в react и не могу понять это.
За последние несколько дней я создал красивую панель мониторинга и хочу добавить страницу данных с транзакциями CRUD. Я хочу изменить текст внутри кнопки поиска, когда состояние формы поиска равно true, но оно работает только после обновления компонента, а не при первом рендеринге. Я инициировал состояние формы поиска с помощью false, а при searchBtnClick состояние устанавливается в true. Но текст внутри кнопки не меняется.
import React, { Component, Fragment } from 'react';
import SideBar from '../../components/navBar/SideBar';
import SearchForm from '../../components/forms/SearchForm';
import TransactionTable from '../../components/tables/TransactionTable';
import './data.css';
import { getTransaction } from '../../actions/Transactions';
export default class Data extends Component {
constructor(props) {
super(props);
this.state = {
year: 0,
month: '',
transactions: [],
searchForm: false,
addForm: false,
editForm: false,
error: false,
errorMessage: '',
};
this.navBtnClick = this.navBtnClick.bind(this);
this.addBtnClick = this.addBtnClick.bind(this);
this.searchBtnClick = this.searchBtnClick.bind(this);
this.editBtnClick = this.editBtnClick.bind(this);
this.deleteBtnClick = this.deleteBtnClick.bind(this);
this.updateTable = this.updateTable.bind(this);
this.setError = this.setError.bind(this);
this.months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
}
componentDidMount() {
const currentDate = new Date();
var currentYear = currentDate.getYear() 1900;
this.setState({ year: currentYear });
var currentMonth = this.months[currentDate.getMonth()].toLowerCase();
this.setState({ month: currentMonth });
getTransaction({ year: currentYear, month: currentMonth }).then((res) => {
if (res.error) {
this.setError(true, res.error);
} else {
this.setError(false);
this.setState({ transactions: res });
}
});
}
navBtnClick() {
this.props.updateNavBarState();
}
addBtnClick(e) {
this.setState({ addForm: !this.state.addForm });
}
searchBtnClick() {
this.setState({ searchForm: !this.state.searchForm });
}
editBtnClick(e) {
this.setState({ editForm: !this.state.editForm });
}
deleteBtnClick(e) {}
updateTable(transactions) {
// If there isn't an error, close the form
if (this.state.error === false) {
this.setState({ transactions: transactions });
this.setState({ addForm: false });
this.setState({ searchForm: false });
this.setState({ editForm: false });
}
}
setError(state, message = '') {
this.setState({ error: state });
this.setState({ errorMessage: message });
}
render() {
return (
<Fragment>
<SideBar sideBarState={this.props.sideBarState} />
<div className="page">
<div className="grid head">
<span id="sidebarCollapseBtn">
<i className="fas fa-align-left" onClick={this.navBtnClick}></i>
</span>
<h1 className="capitalize">data</h1>
</div>
<div className="content">
<div className="card" id="dataCard">
<div className="actions" id="actions">
<div className="flex">
// This if statement
{this.state.searchForm === true ? (
<button
className="search btn"
id="searchBtn"
onClick={this.searchBtnClick}
>
close
</button>
) : (
<button
className="search btn"
id="searchBtn"
onClick={this.searchBtnClick}
>
<i className="fas fa-search mr-025"></i>search
</button>
)}
<button
className="add btn"
id="addBtn"
onClick={this.addBtnClick}
>
<i className="fas fa-plus mr-025"></i>add
</button>
</div>
{this.state.searchForm ? (
<SearchForm
year={this.state.year}
month={this.state.month}
updateTable={this.updateTable}
setError={this.setError}
/>
) : (
<Fragment />
)}
</div>
<div className="output">
{this.state.transactions.length > 1 ? (
<TransactionTable transactions={this.state.transactions} />
) : (
<Fragment />
)}
</div>
</div>
</div>
</div>
</Fragment>
);
}
}
Заранее спасибо,
Марк
Комментарии:
1.
this.state.searchForm
изначально false для первого рендеринга. Вы хотите сказать, что при последующем рендеринге после нажатия кнопки иsearchForm
переключения состояния кнопка не заменяется? Это немного сложно понять, поскольку у вас есть 3 кнопки «поиск» и другой уровень ветвленияthis.state.error
.2. Вы можете игнорировать ветку ошибок. Правильно, что this.state.SearchForm имеет значение false при первом отображении, и когда я нажимаю кнопку поиска, оно меняется на true. Но кнопка не выгружается.
3. Я не вижу никаких явных проблем с логикой переключения в обработчике (кроме того, что это, вероятно, должно быть обновление функционального состояния) и троичным (кроме того, что вам не нужно сравнивать с true / false, поскольку
searchForm
это уже логическое значение). Думаете, вы могли бы создать работающий codesandbox, который воспроизводит проблему?
Ответ №1:
Пара предложений, которые я бы сделал по поводу этого кода:
- Несколько личное предпочтение, использование обозначения со стрелками для определения методов класса, чтобы вам не приходилось
.bind(this)
использовать их для каждого.
// this is the same as
constructor(props) {
this.someFunc = this.someFunc.bind(this)
}
someFunc() {}
// writing just this
someFunc = () => {}
-
Код внутри вашего
if (this.state.error) {}
почти идентичен всему компоненту с некоторыми незначительными изменениями. Я бы посоветовал быть более целенаправленным / конкретным в ваших операторах if и просто изменить наименьшую необходимую часть. (см. Большой код ниже) -
В нескольких местах вы используете тернарный оператор для возврата чего-либо ИЛИ
<Fragment />
. Опять же, это может быть просто личным предпочтением, но вместо этого вы могли бы просто использоватьamp;amp;
для упрощения кода.
// this is the same as
{this.state.searchForm ? (
<MyComponent />
) : (
<Fragment />
)}
// is the same as writing
{this.state.searchForm amp;amp; <MyComponent />}
// or
{this.state.searchForm amp;amp; (
<MyComponent
foo="something"
bar="baz"
onClick={this.onClick}
/>
)}
Вот ваш полный пример кода с примененными упрощениями, приведенными выше.
RE: ваш актуальный вопрос, однако, о том, почему текст не меняется внутри вашей кнопки поиска… ваш обработчик кликов выглядит правильно и должен правильно изменять состояние… Возможно, если использовать оператор if, как я предложил, быть более нацеленным только на изменение фактического текста внутри кнопки, а не всей кнопки, это поможет.
import React, { Component, Fragment } from "react";
import SideBar from "../../components/navBar/SideBar";
import SearchForm from "../../components/forms/SearchForm";
import TransactionTable from "../../components/tables/TransactionTable";
import "./data.css";
import { getTransaction } from "../../actions/Transactions";
export default class Data extends Component {
constructor(props) {
super(props);
this.state = {
year: 0,
month: "",
transactions: [],
searchForm: false,
addForm: false,
editForm: false,
error: false,
errorMessage: "",
};
this.months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
}
componentDidMount() {
const currentDate = new Date();
var currentYear = currentDate.getYear() 1900;
this.setState({ year: currentYear });
var currentMonth = this.months[currentDate.getMonth()].toLowerCase();
this.setState({ month: currentMonth });
getTransaction({ year: currentYear, month: currentMonth }).then((res) => {
if (res.error) {
this.setError(true, res.error);
} else {
this.setError(false);
this.setState({ transactions: res });
}
});
}
navBtnClick = () => {
this.props.updateNavBarState();
};
addBtnClick = (e) => {
this.setState({ addForm: !this.state.addForm });
};
searchBtnClick = () => {
this.setState({ searchForm: !this.state.searchForm });
};
editBtnClick = (e) => {
this.setState({ editForm: !this.state.editForm });
};
deleteBtnClick = (e) => {};
updateTable = (transactions) => {
// If there isn't an error, close the form
if (this.state.error === false) {
this.setState({ transactions: transactions });
this.setState({ addForm: false });
this.setState({ searchForm: false });
this.setState({ editForm: false });
}
};
setError = (state, message = "") => {
this.setState({ error: state });
this.setState({ errorMessage: message });
};
render() {
return (
<Fragment>
<SideBar sideBarState={this.props.sideBarState} />
<div className="page">
<div className="grid head">
<span id="sidebarCollapseBtn">
<i className="fas fa-align-left" onClick={this.navBtnClick}></i>
</span>
<h1 className="capitalize">data</h1>
</div>
<div className="content">
<div className="card" id="dataCard">
<div className="actions" id="actions">
<div className="flex">
<button
className="search btn"
id="searchBtn"
onClick={this.searchBtnClick}
>
{this.state.searchForm ? (
"close"
) : (
<Fragment>
<i className="fas fa-search mr-025"></i>search
</Fragment>
)}
</button>
<button
className="add btn"
id="addBtn"
onClick={this.addBtnClick}
>
<i className="fas fa-plus mr-025"></i>add
</button>
</div>
{this.state.searchForm amp;amp; (
<SearchForm
year={this.state.year}
month={this.state.month}
updateTable={this.updateTable}
setError={this.setError}
/>
)}
</div>
<div className="output">
{this.state.error amp;amp; <h2>{this.state.errorMessage}</h2>}
{this.state.transactions.length > 1 amp;amp; (
<TransactionTable transactions={this.state.transactions} />
)}
</div>
</div>
</div>
</div>
</Fragment>
);
}
}
Комментарии:
1. Спасибо, m8. Я должен больше сосредоточиться на лучшем и более чистом коде!