#javascript #reactjs #redux #material-ui
#reactjs #реагировать-redux #материал-пользовательский интерфейс
Вопрос:
У меня есть этот экспорт рабочего компонента:
export default connect(
mapStateToProps, actions,
null, { withRef: true, forwardRef: true }
)(withTheme()(withStyles(styles)(MainMenu)));
И его вызов:
<MainMenu
ref={(connectedMenu) => this.menuRef = connectedMenu.getWrappedInstance()}
user={user}
/>
Я ожидал получить ссылку на MainMenu, но вместо этого я продолжаю получать с помощью объекта Theme.
Я также пытался пройти через innerRef, но получил следующие ошибки:
TypeError: connectedMenu.getWrappedInstance is not a function
TypeError: Cannot read property 'getWrappedInstance' of null
Перед всем этим я пробовал этот React.createRef()
формат, но он не работал.
Как мне получить эту ссылку?
Ответ №1:
Предполагая, что вы используете версию 4 Material-UI, ваш синтаксис для withTheme
неверен. В версии 4 первый набор круглых скобок был удален.
Вместо
withTheme()(YourComponent)
у вас должно быть
withTheme(YourComponent)
Ниже приведен код из модифицированной версии руководства по списку задач react-redux, который показывает правильный синтаксис. Я включил сюда два файла, которые я изменил (TodoList.js и TodoApp.js ), но песочница — это полностью рабочий пример.
В TodoApp
я использую ссылку на TodoList
, чтобы получить и отобразить ее высоту. Отображаемая высота будет обновляться только при TodoApp
повторном рендеринге, поэтому я включил кнопку для запуска повторного рендеринга. Если вы добавите пару задач в список задач, а затем нажмете кнопку повторного рендеринга, вы увидите, что отображается новая высота списка (показывая, что ссылка полностью работает).
В TodoList
я использую withStyles
для добавления синей рамки вокруг списка задач, чтобы показать, что withStyles
работает, и я отображаю основной цвет из темы, чтобы показать, что withTheme
работает.
TodoList.js
import React from "react";
import { connect } from "react-redux";
import Todo from "./Todo";
import { getTodosByVisibilityFilter } from "../redux/selectors";
import { withStyles, withTheme } from "@material-ui/core/styles";
import clsx from "clsx";
const styles = {
list: {
border: "1px solid blue"
}
};
const TodoList = React.forwardRef(({ todos, theme, classes }, ref) => (
<>
<div>theme.palette.primary.main: {theme.palette.primary.main}</div>
<ul ref={ref} className={clsx("todo-list", classes.list)}>
{todos amp;amp; todos.length
? todos.map((todo, index) => {
return <Todo key={`todo-${todo.id}`} todo={todo} />;
})
: "No todos, yay!"}
</ul>
</>
));
const mapStateToProps = state => {
const { visibilityFilter } = state;
const todos = getTodosByVisibilityFilter(state, visibilityFilter);
return { todos };
};
export default connect(
mapStateToProps,
null,
null,
{ forwardRef: true }
)(withTheme(withStyles(styles)(TodoList)));
TodoApp.js
import React from "react";
import AddTodo from "./components/AddTodo";
import TodoList from "./components/TodoList";
import VisibilityFilters from "./components/VisibilityFilters";
import "./styles.css";
export default function TodoApp() {
const [renderIndex, incrementRenderIndex] = React.useReducer(
prevRenderIndex => prevRenderIndex 1,
0
);
const todoListRef = React.useRef();
const heightDisplayRef = React.useRef();
React.useEffect(() => {
if (todoListRef.current amp;amp; heightDisplayRef.current) {
heightDisplayRef.current.innerHTML = ` (height: ${
todoListRef.current.offsetHeight
})`;
}
});
return (
<div className="todo-app">
<h1>
Todo List
<span ref={heightDisplayRef} />
</h1>
<AddTodo />
<TodoList ref={todoListRef} />
<VisibilityFilters />
<button onClick={incrementRenderIndex}>
Trigger re-render of TodoApp
</button>
<div>Render Index: {renderIndex}</div>
</div>
);
}