Reactjs 使用样式从连接的redux组件获取ref

Reactjs 使用样式从连接的redux组件获取ref,reactjs,react-redux,material-ui,Reactjs,React Redux,Material Ui,我有一个工作组件的导出: export default connect( mapStateToProps, actions, null, { withRef: true, forwardRef: true } )(withTheme()(withStyles(styles)(MainMenu))); 以及它的号召: <MainMenu ref={(connectedMenu) => this.menuRef = connectedMenu.getWrapp

我有一个工作组件的导出:

export default connect(
    mapStateToProps, actions,
    null, { withRef: true, forwardRef: true }
  )(withTheme()(withStyles(styles)(MainMenu)));
以及它的号召:

<MainMenu 
  ref={(connectedMenu) => this.menuRef = connectedMenu.getWrappedInstance()} 
  user={user} 
/>
在此之前,我尝试过
React.createRef()
format,但没有成功


如何获取此引用?

假设您使用的是Material UI的v4,则您的
with theme
语法不正确。在v4中,第一组括号

而不是

withTheme()(YourComponent)
你应该

withTheme(YourComponent)
下面是的修改版本的代码,显示了正确的语法。我在这里包括了我更改的两个文件(TodoList.js和TodoApp.js),但沙箱是一个完全可以工作的示例

TodoApp
中,我使用
TodoList
上的ref获取并显示其高度。显示的高度只有在重新渲染时才会更新,所以我添加了一个按钮来触发重新渲染。如果将两个todo添加到todo列表中,然后单击“重新渲染”按钮,您将看到显示列表的新高度(显示ref完全工作)

TodoList
中,我使用
withStyles
在todo列表周围添加一个蓝色边框,以显示
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 && 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)));
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 && 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>
  );
}

假设您使用的是Material UI的v4,则您的
with theme
语法不正确。在v4中,第一组括号

而不是

withTheme()(YourComponent)
你应该

withTheme(YourComponent)
下面是的修改版本的代码,显示了正确的语法。我在这里包括了我更改的两个文件(TodoList.js和TodoApp.js),但沙箱是一个完全可以工作的示例

TodoApp
中,我使用
TodoList
上的ref获取并显示其高度。显示的高度只有在重新渲染时才会更新,所以我添加了一个按钮来触发重新渲染。如果将两个todo添加到todo列表中,然后单击“重新渲染”按钮,您将看到显示列表的新高度(显示ref完全工作)

TodoList
中,我使用
withStyles
在todo列表周围添加一个蓝色边框,以显示
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 && 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)));
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 && 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>
  );
}