- Оригинальный адрес:8 React conditional rendering methods
- Оригинальный автор:Esteban Herrera
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:Dong Han
- Корректор:Jessica Shao,doctype233
JSX).
如果你想要遍历一个列表来渲染多个组件或者实现一些条件逻辑,你不得不使用纯 Javascript,你也并没有很多的选择来处理循环。 Чаще,map
удовлетворит ваши потребности.
Но как насчет условных выражений?
Это другая история.
Есть несколько вариантов на ваш выбор
В React есть несколько способов использования условных операторов. И, как и в большинстве случаев в программировании, в зависимости от реальной проблемы, которую вы пытаетесь решить, некоторые подходы являются более подходящими.
В этом руководстве рассматриваются наиболее популярные методы условного рендеринга:
- If/Else
- Избегайте рендеринга пустых элементов
- переменная элемента
- Тернарный оператор
- А ТАКЖЕ (&&)
- Немедленный вызов функции (IIFE)
- Подсборка
- Компонент высшего порядка (HOC)
В качестве примера того, как работают все эти методы, далее будут реализованы компоненты с функциями просмотра/редактирования:
ты сможешьJSFiddleПопробуйте разветвить все примеры в .
Давайте начнем с самой примитивной реализации с использованием if/else и построим ее здесь.
If/else
Давайте создадим компонент со следующим состоянием:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
}
}
Вы будете использовать одно свойство для хранения текста, а другое свойство — для хранения редактируемого текста. Третий атрибут будет использоваться для указания того, что вы находитесь вedit
ещеview
режим.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
}
Теперь для метода рендеринга в дополнение к сохраненному тексту проверьте свойство модального состояния, чтобы отобразить кнопку редактирования или поле ввода текста и кнопку сохранения:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
}
Вот полный код, вы можете попробовать его в скрипке:
Babel + JSX:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
render () {
if(this.state.mode === 'view') {
return (
<div>
<p>Text: {this.state.text}</p>
<button onClick={this.handleEdit}>
Edit
</button>
</div>
);
} else {
return (
<div>
<p>Text: {this.state.text}</p>
<input
onChange={this.handleChange}
value={this.state.inputText}
/>
<button onClick={this.handleSave}>
Save
</button>
</div>
);
}
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Если / else самый простой способ решить это, но я уверен, что вы знаете, что это не хороший способ сделать это.
Это работает для простых случаев использования, и каждый программист знает, как это работает. Но есть много повторений,render
class App extends React.Component {
// …
renderInputField() {
if(this.state.mode === 'view') {
return <div></div>;
} else {
return (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText}
/>
</p>
);
}
}
renderButton() {
if(this.state.mode === 'view') {
return (
<button onClick={this.handleEdit}>
Edit
</button>
);
} else {
return (
<button onClick={this.handleSave}>
Save
</button>
);
}
}
render () {
return (
<div>
<p>Text: {this.state.text}</p>
{this.renderInputField()}
{this.renderButton()}
</div>
);
}
}
Вот полный код, вы можете попробовать его в скрипке:
Babel + JSX:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
renderInputField() {
if(this.state.mode === 'view') {
return <div></div>;
} else {
return (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText}
/>
</p>
);
}
}
renderButton() {
if(this.state.mode === 'view') {
return (
<button onClick={this.handleEdit}>
Edit
</button>
);
} else {
return (
<button onClick={this.handleSave}>
Save
</button>
);
}
}
render () {
return (
<div>
<p>Text: {this.state.text}</p>
{this.renderInputField()}
{this.renderButton()}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
renderInputField
вернулся пустойdiv
элемент.
Однако это не нужно.
Избегайте рендеринга пустых элементов
Если хочешьСпрятатькомпонент, вы можете вернуть его метод рендерингаnull
Потому что нет необходимости рендерить пустой (и другой) элемент на место.
null
Например, между двумя компонентами реализован следующий счетчик кода:
Babel + JSX:
class Number extends React.Component {
constructor(props) {
super(props);
}
componentDidUpdate() {
console.log('componentDidUpdate');
}
render() {
if(this.props.number % 2 == 0) {
return (
<div>
<h1>{this.props.number}</h1>
</div>
);
} else {
return null;
}
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 }
}
onClick(e) {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
render() {
return (
<div>
<Number number={this.state.count} />
<button onClick={this.onClick.bind(this)}>Count</button>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Number
Компонент отображает значение, переданное родительским компонентом, только если родительский компонент передает четное число, в противном случае он вернетnull
. Затем, глядя на вывод консоли, вы увидите, что независимо отrender
что вернуть,componentDidUpdate
всегда будут вызывать.
Возвращаясь к нашему примеру, измените его следующим образом.renderInputField
метод:
renderInputField() {
if(this.state.mode === 'view') {
return null;
} else {
return (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText}
/>
</p>
);
}
}
Вот полный код:
Babel + JSX:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
renderInputField() {
if(this.state.mode === 'view') {
return null;
} else {
return (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText}
/>
</p>
);
}
}
renderButton() {
if(this.state.mode === 'view') {
return (
<button onClick={this.handleEdit}>
Edit
</button>
);
} else {
return (
<button onClick={this.handleSave}>
Save
</button>
);
}
}
render () {
return (
<div>
<p>Text: {this.state.text}</p>
{this.renderInputField()}
{this.renderButton()}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
вернутьnull
Преимущество замены пустого элемента заключается в том, что это немного улучшит производительность компонента, поскольку React не нужно отвязывать компонент, чтобы заменить его.
Например, при выполнении возврата пустымdiv
Когда код элемента открыт, откройте элемент страницы проверки, и вы увидитеdiv
Как элемент обновляется:
В отличие от этого примера, при возвратеnull
скрыть компоненты,Edit
когда кнопка нажатаdiv
Элементы не обновляются:
здесь, вы узнаете больше о том, как React обновляет элементы DOM и как работает алгоритм «сравнения».
Может быть, в этом простом примере повышение производительности тривиально, но когда в компоненте, который нужно часто обновлять, ситуация будет другой.
Последствия условного рендеринга для производительности подробно обсуждаются позже. Теперь давайте перейдем к улучшению этого примера.
переменная элемента
Одна вещь, которую я не люблю, это наличие более одного метода в одном методе.return
утверждение.
true
renderInputField() {
let input;
if(this.state.mode !== 'view') {
input =
<p>
<input
onChange={this.handleChange}
value={this.state.inputText} />
</p>;
}
return input;
}
renderButton() {
let button;
if(this.state.mode === 'view') {
button =
<button onClick={this.handleEdit}>
Edit
</button>;
} else {
button =
<button onClick={this.handleSave}>
Save
</button>;
}
return button;
}
null
Метод.
Babel + JSX:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
renderInputField() {
let input;
if(this.state.mode !== 'view') {
input =
<p>
<input
onChange={this.handleChange}
value={this.state.inputText} />
</p>;
}
return input;
}
renderButton() {
let button;
if(this.state.mode === 'view') {
button =
<button onClick={this.handleEdit}>
Edit
</button>;
} else {
button =
<button onClick={this.handleSave}>
Save
</button>;
}
return button;
}
render () {
return (
<div>
<p>Text: {this.state.text}</p>
{this.renderInputField()}
{this.renderButton()}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Используйте этот способ, чтобы сделать основнойrender
метод более удобочитаем, но, возможно, нет необходимости использовать тест if/else (или что-то вродеswitch
такие операторы) и вспомогательные методы рендеринга.
Попробуем более простой способ.
Тернарный оператор
мы можем использоватьТернарный операторвместо оператора if/else:
condition ? expr_if_true : expr_if_false
Оператор заключен в фигурные скобки, а выражения могут содержать JSX, опционально заключенные в круглые скобки для удобства чтения.
Он может быть применен к различным частям компонента. Давайте применим это к примеру, чтобы вы могли увидеть это в действии.
я буду вrender
метод удаленrenderInputField
а такжеrenderButton
и добавьте переменную, чтобы указать, что компонент находится вview
ещеedit
модель:
render () {
const view = this.state.mode === 'view';
return (
<div>
</div>
);
}
Теперь вы можете использовать Ternary Operator, когда узел предоставленview
Вернуться в режимnull
// ...
return (
<div>
<p>Text: {this.state.text}</p>
{
view
? null
: (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText} />
</p>
)
}
</div>
);
// ...
return (
<div>
<p>Text: {this.state.text}</p>
{
...
}
<button
onClick={
view
? this.handleEdit
: this.handleSave
} >
{view ? 'Edit' : 'Save'}
</button>
</div>
);
Вы можете увидеть эффекты в эксплуатации Widdle в:
JS fiddle.net/worst 3 soft и ah/has 6…
И оператор
В частном случае тернарный оператор можно упростить.
Когда вы хотите сделать элемент в одном состоянии, а не в другом, вы можете использовать&&
оператор.
отличный от&
оператор, когда выражение слева может определить окончательный результат,&&
Решение правого выражения больше не будет выполняться.
Например, если первое выражение оценивается как false (false && …
), нет необходимости вычислять следующее выражение, потому что результат всегда будетfalse
.
В React вы можете использовать такие выражения:
return (
<div>
{ showHeader && <Header /> }
</div>
);
еслиshowHeader
считаетсяtrue
,<Header/>
Компонент будет возвращен этим выражением.
еслиshowHeader
считаетсяfalse
,<Header/>
div
Это будет возвращено.
{
view
? null
: (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText} />
</p>
)
}
!view && (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText} />
</p>
)
Вот полный код, исполняемый в скрипте:
Banel + JSX:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
render () {
const view = this.state.mode === 'view';
return (
<div>
<p>Text: {this.state.text}</p>
{
!view && (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText} />
</p>
)
}
<button
onClick={
view
? this.handleEdit
: this.handleSave
}
>
{view ? 'Edit' : 'Save'}
</button>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Выглядит лучше, не так ли?
Однако тернарные выражения не всегда выглядят так хорошо.
Рассмотрим сложный набор вложенных условий:
return (
<div>
{ condition1
? <Component1 />
: ( condition2
? <Component2 />
: ( condition3
? <Component3 />
: <Component 4 />
)
)
}
</div>
);
Это может быстро запутаться.
По этой причине иногда вы можете захотеть использовать другие методы, такие как немедленное выполнение функции.
Выражение немедленного выполнения функции (IIFE)
Как следует из названия, непосредственные функции — это функции, которые вызываются сразу после их определения, их не нужно вызывать явно.
Обычно вы определяете и выполняете (выполняете после определения) такую функцию:
function myFunction() {
// ...
}
myFunction();
Но если вы хотите выполнить функцию сразу после ее определения, вы должны обернуть функцию парой круглых скобок (преобразовав ее в выражение) и выполнить ее, добавив еще две круглые скобки (внутри круглых скобок вы можете передать то, что нужно функции любые параметры).
так:
( function myFunction(/* arguments */) {
// ...
}(/* arguments */) );
или это:
( function myFunction(/* arguments */) {
// ...
} ) (/* arguments */);
Поскольку эта функция больше нигде не будет вызываться, имя функции можно опустить:
( function (/* arguments */) {
// ...
} ) (/* arguments */);
Или вы также можете использовать функции стрелок:
( (/* arguments */) => {
// ...
} ) (/* arguments */);
В React вы можете использовать фигурные скобки, чтобы обернуть немедленно выполняемую функцию, написать всю необходимую логику внутри функции (если/иначе, переключатель, тернарные операторы и т. д.) и вернуть все, что вы хотите отобразить.
Например, следующая функция немедленного выполнения — это логика того, как определить, отображать ли кнопку сохранения или редактирования:
{
(() => {
const handler = view
? this.handleEdit
: this.handleSave;
const label = view ? 'Edit' : 'Save';
return (
<button onClick={handler}>
{label}
</button>
);
})()
}
Вот полный код может быть выполнен в скрипке в:
Babel + JSX:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
render () {
const view = this.state.mode === 'view';
return (
<div>
<p>Text: {this.state.text}</p>
{
!view && (
<p>
<input
onChange={this.handleChange}
value={this.state.inputText} />
</p>
)
}
{
(() => {
const handler = view
? this.handleEdit
: this.handleSave;
const label = view ? 'Edit' : 'Save';
return (
<button onClick={handler}>
{label}
</button>
);
})()
}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<div id="root"></div>
Подсборка
В конце концов, мы используем React, рекомендуемое решение React состоит в том, чтобы разбить логику вашего приложения на максимальное количество компонентов, и рекомендуется функциональное программирование, а не императивное программирование.
Поэтому измените логику условного рендеринга в качестве дочернего компонента, этот дочерний компонент будет определять рендеринг в разных ситуациях в соответствии с реквизитами, переданными родительским компонентом, что будет лучшим решением.
Но здесь я собираюсь сделать кое-что немного другое и показать вам, как перейти от императивного решения к более декларативному и функциональному решению.
я создамSaveComponent
Компоненты начинаются:
const SaveComponent = (props) => {
return (
<div>
<p>
<input
onChange={props.handleChange}
value={props.text}
/>
</p>
<button onClick={props.handleSave}>
Save
</button>
</div>
);
};
Как функциональные атрибуты программирования,SaveComponent
Функциональная логика функции выводится из параметров, заданных параметрами, которые она получает. Таким же образом определите другой компонентEditComponent
:
const EditComponent = (props) => {
return (
<button onClick={props.handleEdit}>
Edit
</button>
);
};
Сейчасrender
Метод становится таким:
render () {
const view = this.state.mode === 'view';
return (
<div>
<p>Text: {this.state.text}</p>
{
view
? <EditComponent handleEdit={this.handleEdit} />
: (
<SaveComponent
handleChange={this.handleChange}
handleSave={this.handleSave}
text={this.state.inputText}
/>
)
}
</div>
);
}
Вот полный код, который можно выполнить в скрипте:
Babel + JSX:
const SaveComponent = (props) => {
return (
<div>
<p>
<input
onChange={props.handleChange}
value={props.text}
/>
</p>
<button onClick={props.handleSave}>
Save
</button>
</div>
);
};
const EditComponent = (props) => {
return (
<button onClick={props.handleEdit}>
Edit
</button>
);
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
render () {
const view = this.state.mode === 'view';
return (
<div>
<p>Text: {this.state.text}</p>
{
view
? <EditComponent handleEdit={this.handleEdit} />
: (
<SaveComponent
handleChange={this.handleChange}
handleSave={this.handleSave}
text={this.state.inputText}
/>
)
}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Если компоненты
подобноjsx-control-statementsТакие библиотеки могут расширять JSX, добавляя следующее:
<If condition={ true }>
<span>Hi!</span>
</If>
Эти библиотеки предоставляют более продвинутые компоненты, но если нам нужны простые if/else, мы можем обратиться кMichael J. RyanсуществуетissueвнизКомментарий:
const If = (props) => {
const condition = props.condition || false;
const positive = props.then || null;
const negative = props.else || null;
return condition ? positive : negative;
};
// …
render () {
const view = this.state.mode === 'view';
const editComponent = <EditComponent handleEdit={this.handleEdit} />;
const saveComponent = <SaveComponent
handleChange={this.handleChange}
handleSave={this.handleSave}
text={this.state.inputText}
/>;
return (
<div>
<p>Text: {this.state.text}</p>
<If
condition={ view }
then={ editComponent }
else={ saveComponent }
/>
</div>
);
}
Вот полный код, который можно выполнить в скрипте:
Babel + JSX:
const SaveComponent = (props) => {
return (
<div>
<p>
<input
onChange={props.handleChange}
value={props.text}
/>
</p>
<button onClick={props.handleSave}>
Save
</button>
</div>
);
};
const EditComponent = (props) => {
return (
<button onClick={props.handleEdit}>
Edit
</button>
);
};
const If = (props) => {
const condition = props.condition || false;
const positive = props.then || null;
const negative = props.else || null;
return condition ? positive : negative;
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
render () {
const view = this.state.mode === 'view';
const editComponent = <EditComponent handleEdit={this.handleEdit} />;
const saveComponent = <SaveComponent
handleChange={this.handleChange}
handleSave={this.handleSave}
text={this.state.inputText}
/>;
return (
<div>
<p>Text: {this.state.text}</p>
<If
condition={ view }
then={ editComponent }
else={ saveComponent }
/>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
компоненты более высокого порядка
компоненты более высокого порядка(HOC) — это функция, которая берет существующий компонент и возвращает новый компонент с дополнительными функциями на основе этого компонента:
const EnhancedComponent = higherOrderComponent(component);
При применении к условию рендеринга компонент более высокого порядка передается компоненту, компонент более высокого порядка может собираться в соответствии с некоторыми исходными компонентами, чтобы вернуть условие, отличное от:
function higherOrderComponent(Component) {
return function EnhancedComponent(props) {
if (condition) {
return <AnotherComponent { ...props } />;
}
return <Component { ...props } />;
};
}
Вот статьяRobin WieruchнаписаноЗамечательная хорошая статья о компонентах высокого порядка
EitherComponent
Концепция чего-либо.
Either
Итак, давайте начнем с определения функции, которая принимает два аргумента, и еще одной функции, которая возвращает логическое значение (результат условия), если логическое значение равноtrue
затем возвращает компонент:
function withEither(conditionalRenderingFn, EitherComponent) {
}
Обычно имя функции компонентов высокого порядкаwith
начало.
Эта функция вернет другую функцию, которая берет исходный компонент и возвращает новый компонент:
function withEither(conditionalRenderingFn, EitherComponent) {
return function buildNewComponent(Component) {
}
}
Этот компонент (функция), возвращаемый внутренней функцией, — это то, что вы будете использовать в своем приложении, поэтому он получает объект со всеми свойствами, необходимыми для работы:
function withEither(conditionalRenderingFn, EitherComponent) {
return function buildNewComponent(Component) {
return function FinalComponent(props) {
}
}
}
Внутренняя функция может получить доступ к параметрам внешней функции, поэтому в соответствии с функциейconditionalRenderingFn
EitherComponent
Component
:
function withEither(conditionalRenderingFn, EitherComponent) {
return function buildNewComponent(Component) {
return function FinalComponent(props) {
return conditionalRenderingFn(props)
? <EitherComponent { ...props } />
: <Component { ...props } />;
}
}
}
const withEither = (conditionalRenderingFn, EitherComponent) => (Component) => (props) =>
conditionalRenderingFn(props)
? <EitherComponent { ...props } />
: <Component { ...props } />;
Кстати, используйте оригинальное определениеSaveComponent
а такжеEditComponent
Вы можете создатьwithEditConditionalRendering
Компоненты более высокого порядка, и с помощью которых можно создатьEditSaveWithConditionalRendering
Компоненты:
const isViewConditionFn = (props) => props.mode === 'view';
const withEditContionalRendering = withEither(isViewConditionFn, EditComponent);
const EditSaveWithConditionalRendering = withEditContionalRendering(SaveComponent);
Таким образом, вы просто используете компонент в методе рендеринга и передаете ему все необходимые свойства:
render () {
return (
<div>
<p>Text: {this.state.text}</p>
<EditSaveWithConditionalRendering
mode={this.state.mode}
handleEdit={this.handleEdit}
handleChange={this.handleChange}
handleSave={this.handleSave}
text={this.state.inputText}
/>
</div>
);
}
Вот полный код, который можно выполнить в скрипте:
Babel + JSX:
const SaveComponent = (props) => {
return (
<div>
<p>
<input
onChange={props.handleChange}
value={props.text}
/>
</p>
<button onClick={props.handleSave}>
Save
</button>
</div>
);
};
const EditComponent = (props) => {
return (
<button onClick={props.handleEdit}>
Edit
</button>
);
};
const withEither = (conditionalRenderingFn, EitherComponent) => (Component) => (props) =>
conditionalRenderingFn(props)
? <EitherComponent { ...props } />
: <Component { ...props } />;
const isViewConditionFn = (props) => props.mode === 'view';
const withEditContionalRendering = withEither(isViewConditionFn, EditComponent);
const EditSaveWithConditionalRendering = withEditContionalRendering(SaveComponent);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', inputText: '', mode:'view'};
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleChange(e) {
this.setState({ inputText: e.target.value });
}
handleSave() {
this.setState({text: this.state.inputText, mode: 'view'});
}
handleEdit() {
this.setState({mode: 'edit'});
}
render () {
return (
<div>
<p>Text: {this.state.text}</p>
<EditSaveWithConditionalRendering
mode={this.state.mode}
handleEdit={this.handleEdit}
handleChange={this.handleChange}
handleSave={this.handleSave}
text={this.state.inputText}
/>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Вопросы производительности
Условный рендеринг может быть сложным. Как я показал ранее, производительность каждого подхода также может быть разной.
Однако в большинстве случаев эта разница не является проблемой. Но когда это действительно вызывает проблемы, вам нужно иметь четкое представление о том, как работает виртуальный DOM React, и использовать несколько приемов, чтобыОптимизация производительности.
Вот хорошая статья оОптимизация условного рендеринга React, очень рекомендую прочитать.
Основная идея заключается в том, что условный рендеринг, приводящий к изменению положения компонента, вызовет перекомпоновку, что приведет к отвязке/привязке компонентов в приложении.
На основе примеров из этого поста я написал два примера:
В первом примере используется if/else для управленияSubHeader
Babel + JSX:
const Header = (props) => {
return <h1>Header</h1>;
}
const Subheader = (props) => {
return <h2>Subheader</h2>;
}
const Content = (props) => {
return <p>Content</p>;
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
if(this.state.isToggleOn) {
return (
<div>
<Header />
<Subheader />
<Content />
<button onClick={this.handleClick}>
{ this.state.isToggleOn ? 'ON' : 'OFF' }
</button>
</div>
);
} else {
return (
<div>
<Header />
<Content />
<button onClick={this.handleClick}>
{ this.state.isToggleOn ? 'ON' : 'OFF' }
</button>
</div>
);
}
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
&&
Babel + JSX:
const Header = (props) => {
return <h1>Header</h1>;
}
const Subheader = (props) => {
return <h2>Subheader</h2>;
}
const Content = (props) => {
return <p>Content</p>;
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<div>
<Header />
{ this.state.isToggleOn && <Subheader /> }
<Content />
<button onClick={this.handleClick}>
{ this.state.isToggleOn ? 'ON' : 'OFF' }
</button>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Content
В заключение
Как и многие вещи в программировании, существует много способов реализации условного рендеринга в реакцию.
Я бы сказал, что кроме первого способа (существует несколько возвратов if/else) вы можете делать все, что захотите.
Основываясь на следующих принципах, вы можете решить, какой подход лучше всего подходит в вашей реальной ситуации:
- ваш стиль программирования
- Условная логическая сложность
- Удобство работы с JavaScript, JSX и передовыми концепциями React, такими как компоненты высшего порядка.
Если все равны, стремитесь к простоте и удобочитаемости.
Plug: LogRocket, a DVR for web apps
LogRocketЭто интерфейсный инструмент ведения журнала, который может воспроизвести проблему в вашем собственном браузере. Вместо того, чтобы гадать, почему произошла ошибка, или пользователь хочет захватить и зарегистрировать, LogRocket поможет вам заново пережить короля, чтобы быстро понять, что пошло не так. Он подходит для любого приложения, и не зависит от фрейма и, и имеет от Redux, Vuex и @ngrx/store записи других контекстов plug.
Бесплатная пробная версия.
Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.