Bài 08-Những câu hỏi thường gặp
Bạn gặp vấn đề cụ thể nào đó? Hãy kiểm tra một số lỗi thường gặp này trước trong phần Câu hỏi thường gặp.
Dành cho Figma . Một bộ UI lớn với hơn 600 thành phần Material UI, MUI X, Joy UI được làm thủ công 🎨.quảng cáo của MUI
Nếu bạn vẫn không tìm thấy những gì mình đang tìm kiếm, bạn có thể tham khảo trang hỗ trợ của chúng tôi .
MUI là một tổ chức tuyệt vời. Tôi có thể hỗ trợ tổ chức này như thế nào?
Có nhiều cách để hỗ trợ chúng tôi:
- Truyền bá thông tin . Truyền bá sản phẩm của MUI bằng cách liên kết đến mui.com trên trang web của bạn—mọi liên kết ngược đều quan trọng. Theo dõi chúng tôi trên X , thích và chia sẻ lại tin tức quan trọng. Hoặc chỉ cần nói về chúng tôi với bạn bè của bạn.
- Hãy cho chúng tôi phản hồi . Hãy cho chúng tôi biết điều gì đang diễn ra tốt đẹp hoặc có cơ hội cải thiện ở đâu. Hãy bình chọn (👍) cho các vấn đề mà bạn quan tâm nhất để được giải quyết.
- Giúp người dùng mới . Bạn có thể trả lời các câu hỏi trên Stack Overflow .
- Thực hiện thay đổi .
- Chỉnh sửa tài liệu. Ở cuối mỗi trang, bạn có thể tìm thấy nút "Chỉnh sửa trang này".
- Báo cáo lỗi hoặc tính năng bị thiếu bằng cách tạo sự cố .
- Xem xét và bình luận về các yêu cầu kéo và vấn đề hiện có .
- Cải thiện tài liệu , sửa lỗi hoặc thêm tính năng bằng cách gửi yêu cầu kéo .
- Hỗ trợ chúng tôi về mặt tài chính trên Open Collective . Nếu bạn sử dụng Material UI trong một dự án thương mại và muốn hỗ trợ sự phát triển liên tục của dự án bằng cách trở thành Nhà tài trợ, hoặc trong một dự án phụ hoặc sở thích và muốn trở thành Người ủng hộ, bạn có thể thực hiện thông qua Open Collective. Tất cả các khoản tiền quyên góp đều được quản lý minh bạch và Nhà tài trợ sẽ được ghi nhận trong README và trên trang chủ.
Tại sao các thành phần cố định lại di chuyển khi mở hộp thoại?
Cuộn bị chặn ngay khi một modal được mở. Điều này ngăn chặn tương tác với nền khi modal phải là nội dung tương tác duy nhất. Tuy nhiên, việc xóa thanh cuộn có thể khiến các thành phần cố định của bạn di chuyển. Trong trường hợp này, bạn có thể áp dụng .mui-fixedtên lớp toàn cục để yêu cầu Material UI xử lý các thành phần đó.
Làm thế nào tôi có thể vô hiệu hóa hiệu ứng lan tỏa trên toàn cầu?
Hiệu ứng gợn sóng chỉ xuất phát từ BaseButtonthành phần. Bạn có thể vô hiệu hóa hiệu ứng gợn sóng trên toàn cầu bằng cách cung cấp thông tin sau trong chủ đề của bạn:
import { createTheme } from '@mui/material';
const theme = createTheme({
components: {
// Name of the component ⚛️
MuiButtonBase: {
defaultProps: {
// The props to apply
disableRipple: true, // No more ripple, on the whole application 💣!
},
},
},
});
Sao chép
Làm thế nào tôi có thể vô hiệu hóa chuyển tiếp trên toàn cầu?
Material UI sử dụng cùng một trình trợ giúp chủ đề để tạo tất cả các chuyển tiếp của nó. Do đó, bạn có thể vô hiệu hóa tất cả các chuyển tiếp bằng cách ghi đè trình trợ giúp trong chủ đề của bạn:
import { createTheme } from '@mui/material';
const theme = createTheme({
transitions: {
// So `transition: none;` gets applied everywhere
create: () => 'none',
},
});
Sao chép
Có thể hữu ích khi vô hiệu hóa các chuyển tiếp trong quá trình kiểm tra trực quan hoặc cải thiện hiệu suất trên các thiết bị cấp thấp.
Bạn có thể tiến thêm một bước nữa bằng cách vô hiệu hóa tất cả các hiệu ứng chuyển tiếp và hoạt ảnh:
import { createTheme } from '@mui/material';
const theme = createTheme({
components: {
// Name of the component ⚛️
MuiCssBaseline: {
styleOverrides: {
'*, *::before, *::after': {
transition: 'none !important',
animation: 'none !important',
},
},
},
},
});
Sao chép
Lưu ý rằng việc sử dụng CssBaselinelà bắt buộc để cách tiếp cận trên hoạt động. Nếu bạn chọn không sử dụng, bạn vẫn có thể vô hiệu hóa các chuyển tiếp và hoạt ảnh bằng cách bao gồm các quy tắc CSS sau:
*,
*::before,
*::after {
transition: 'none !important';
animation: 'none !important';
}
Sao chép
Tôi có phải sử dụng Emotion để tạo kiểu cho ứng dụng của mình không?
Không, không bắt buộc. Nhưng nếu bạn sử dụng engine theo kiểu mặc định ( @mui/styled-engine) thì sự phụ thuộc Emotion được tích hợp sẵn, do đó không phát sinh thêm chi phí về kích thước gói.
Tuy nhiên, có lẽ bạn đang thêm một số thành phần Material UI vào một ứng dụng đã sử dụng giải pháp tạo kiểu khác hoặc đã quen thuộc với một API khác và không muốn tìm hiểu API mới? Trong trường hợp đó, hãy chuyển đến phần khả năng tương tác của thư viện Kiểu để tìm hiểu cách tạo lại kiểu cho các thành phần Material UI bằng các thư viện kiểu thay thế.
Khi nào tôi nên sử dụng inline-style so với CSS?
Theo nguyên tắc chung, chỉ sử dụng inline-styles cho các thuộc tính kiểu động. Giải pháp thay thế CSS cung cấp nhiều lợi thế hơn, chẳng hạn như:
- tự động thêm tiền tố
- gỡ lỗi tốt hơn
- truy vấn phương tiện truyền thông
- khung hình chính
Làm thế nào để sử dụng react-router?
Truy cập hướng dẫn về tích hợp với các thư viện định tuyến của bên thứ ba , như react-router hoặc Next.js, để biết thêm chi tiết.
Làm thế nào tôi có thể truy cập vào phần tử DOM?
Tất cả các thành phần Material UI cần hiển thị một cái gì đó trong DOM sẽ chuyển tiếp tham chiếu của chúng đến thành phần DOM cơ bản. Điều này có nghĩa là bạn có thể lấy các phần tử DOM bằng cách đọc tham chiếu được đính kèm vào các thành phần Material UI:
// or a ref setter function
const ref = React.createRef();
// render
<Button ref={ref} />;
// usage
const element = ref.current;
Sao chép
Nếu bạn không chắc chắn liệu thành phần Material UI có chuyển tiếp tham chiếu của nó hay không, bạn có thể kiểm tra tài liệu API trong mục "Props". Bạn sẽ thấy thông báo bên dưới, giống như trong Button API .
Tham chiếu được chuyển tiếp đến phần tử gốc.
Ứng dụng của tôi không hiển thị đúng trên máy chủ
Nếu không hoạt động, trong 99% trường hợp, đó là vấn đề về cấu hình. Thuộc tính bị thiếu, lệnh gọi sai hoặc thành phần bị thiếu – kết xuất phía máy chủ nghiêm ngặt về cấu hình.
Cách tốt nhất để tìm ra lỗi là so sánh dự án của bạn với một thiết lập đang hoạt động . Kiểm tra các triển khai tham chiếu , từng chút một.
Tại sao màu sắc tôi nhìn thấy lại khác với màu sắc tôi thấy ở đây?
Trang web tài liệu đang sử dụng một chủ đề tùy chỉnh. Do đó, bảng màu khác với chủ đề mặc định mà Material UI cung cấp. Vui lòng tham khảo trang này để tìm hiểu về tùy chỉnh chủ đề.
Tại sao thành phần X lại yêu cầu một nút DOM trong một prop thay vì một đối tượng ref?
Các thành phần như Portal hoặc Popper yêu cầu một nút DOM trong prop containerhoặc anchorEltương ứng. Có vẻ thuận tiện khi chỉ cần truyền một đối tượng ref vào các prop đó và để Material UI truy cập giá trị hiện tại.
Điều này có hiệu quả trong một tình huống đơn giản:
function App() {
const container = React.useRef(null);
return (
<div className="App">
<Portal container={container}>
<span>portaled children</span>
</Portal>
<div ref={container} />
</div>
);
}
Sao chép
nơi Portalsẽ chỉ gắn các con vào container khi container.currentcó sẵn. Đây là một triển khai đơn giản của Portal:
function Portal({ children, container }) {
const [node, setNode] = React.useState(null);
React.useEffect(() => {
setNode(container.current);
}, [container]);
if (node === null) {
return null;
}
return ReactDOM.createPortal(children, node);
}
Sao chép
Với phương pháp tìm kiếm đơn giản này, Portalcó thể render lại sau khi mount vì ref được cập nhật trước khi bất kỳ hiệu ứng nào chạy. Tuy nhiên, chỉ vì ref được cập nhật không có nghĩa là nó trỏ đến một thể hiện đã xác định. Nếu ref được đính kèm vào một thành phần chuyển tiếp ref thì không rõ khi nào nút DOM sẽ khả dụng. Trong ví dụ trên, sẽ Portalchạy một hiệu ứng một lần, nhưng có thể không render lại vì ref.currentvẫn là null. Điều này đặc biệt rõ ràng đối với các thành phần React.lazy trong Suspense. Việc triển khai ở trên cũng có thể không tính đến sự thay đổi trong nút DOM.
Đây là lý do tại sao cần có prop cho nút DOM thực tế để React có thể xác định thời điểm Portalnên hiển thị lại:
function App() {
const [container, setContainer] = React.useState(null);
const handleRef = React.useCallback(
(instance) => setContainer(instance),
[setContainer],
);
return (
<div className="App">
<Portal container={container}>
<span>Portaled</span>
</Portal>
<div ref={handleRef} />
</div>
);
}
Sao chép
Sự phụ thuộc của clsx dùng để làm gì?
clsx là một tiện ích nhỏ để xây dựng classNamechuỗi có điều kiện, từ một đối tượng có khóa là chuỗi lớp và giá trị là boolean.
Thay vì viết:
// let disabled = false, selected = true;
return (
<div
className={`MuiButton-root ${disabled ? 'Mui-disabled' : ''} ${
selected ? 'Mui-selected' : ''
}`}
/>
);
Sao chép
bạn có thể làm:
import clsx from 'clsx';
return (
<div
className={clsx('MuiButton-root', {
'Mui-disabled': disabled,
'Mui-selected': selected,
})}
/>
);
Sao chép
Tôi không thể sử dụng các thành phần làm bộ chọn trong tiện ích styled(). Tôi nên làm gì?
Nếu bạn gặp lỗi: TypeError: Cannot convert a Symbol value to a string, hãy xem trang tài liệu styled() để biết hướng dẫn về cách khắc phục lỗi này.
Tôi có thể đóng góp vào các mẫu miễn phí như thế nào?
Các mẫu được xây dựng bằng cách sử dụng một chủ đề được chia sẻ . Dưới đây là cấu trúc để tạo một mẫu mới:
Trang mẫu
Tạo một trang mới trong docs/pages/material-ui/getting-started/templates/<name>.jsthư mục với mã sau:
import * as React from 'react';
import AppTheme from 'docs/src/modules/components/AppTheme';
import TemplateFrame from 'docs/src/modules/components/TemplateFrame';
import Template from 'docs/data/material/getting-started/templates/<name>/<Template>';
export default function Page() {
return (
<AppTheme>
<TemplateFrame>
<Template />
</TemplateFrame>
</AppTheme>
);
}
Sao chép
Sau đó tạo một tệp mẫu tại docs/data/material/getting-started/templates/<name>/<Template>.tsx(thêm tệp nếu cần):
Lưu ý:
<Template>Chuỗi ký tự của thư mục phải là chữ hoa pascal<name>.
Chủ đề chia sẻ
Mẫu phải sử dụng AppThemefrom ../shared-theme/AppThemeđể đảm bảo giao diện nhất quán trên tất cả các mẫu.
Nếu mẫu bao gồm các thành phần theo chủ đề tùy chỉnh, chẳng hạn như mẫu bảng điều khiển có các thành phần theo chủ đề MUI X, hãy truyền chúng cho thuộc tính AppTheme's themedComponents:
import AppTheme from '../shared-theme/AppTheme';
const xThemeComponents = {
...chartsCustomizations,
...dataGridCustomizations,
...datePickersCustomizations,
...treeViewCustomizations,
};
export default function Dashboard(props: { disableCustomTheme?: boolean }) {
return (
<AppTheme {...props} themeComponents={xThemeComponents}>...</AppTheme>
)
}
Sao chép
Chuyển đổi chế độ màu
Chủ đề được chia sẻ cung cấp 2 giao diện của chế độ chuyển đổi màu ColorModeSelectvà ColorModeIconDropdown. Bạn có thể sử dụng bất kỳ giao diện nào trong mẫu của mình, giao diện này sẽ ẩn trong TemplateFramenhưng sẽ hiển thị trong Code Sandbox và Stackblitz.
Khung mẫu
Nếu mẫu có thanh bên hoặc tiêu đề cần dính vào đầu, hãy tham khảo biến CSS --template-frame-heightđể điều chỉnh.
Ví dụ, mẫu bảng điều khiển có tiêu đề cố định cần được tính đến theo chiều cao của khung mẫu:
<AppBar
position="fixed"
sx={{
top: 'var(--template-frame-height, 0px)',
// ...other styles
}}
>
Sao chép
Thao tác này sẽ giữ nguyên nội AppBardung bên dưới TemplateFramechế độ xem trước nhưng vẫn nằm ở đầu trong CodeSandbox và Stackblitz.
[di sản] Tôi có một số trường hợp kiểu trên trang
Nếu bạn thấy thông báo cảnh báo trong bảng điều khiển như bên dưới, có thể bạn có một số trường hợp @mui/styleskhởi tạo trên trang.
Có vẻ như có một số trường hợp @mui/styleskhởi tạo trong ứng dụng này. Điều này có thể gây ra sự cố truyền bá chủ đề, tên lớp bị hỏng, sự cố về t ính cụ thể và làm cho ứng dụng của bạn lớn hơn mà không có lý do chính đáng.
Những lý do có thể
Có một số lý do phổ biến khiến điều này xảy ra:
- Bạn có một
@mui/stylesthư viện khác ở đâu đó trong phần phụ thuộc của mình. - Bạn có một cấu trúc monorepo cho dự án của mình (ví dụ: không gian làm việc lerna hoặc yarn) và
@mui/stylesmodule là một phần phụ thuộc trong nhiều gói (gói này ít nhiều giống với gói trước). - Bạn có nhiều ứng dụng đang
@mui/styleschạy trên cùng một trang (ví dụ: nhiều điểm vào trong Webpack được tải trên cùng một trang).
Mô-đun trùng lặp trong node_modules
Nếu bạn nghĩ rằng vấn đề có thể nằm ở việc trùng lặp mô-đun @mui/styles ở đâu đó trong các dependency của bạn, có một số cách để kiểm tra điều này. Bạn có thể sử dụng lệnh npm ls @mui/styles, yarn list @mui/styleshoặc find -L ./node_modules | grep /@mui/styles/package.jsontrong thư mục ứng dụng của mình.
Nếu không có lệnh nào trong số các lệnh này xác định được sự trùng lặp, hãy thử phân tích gói của bạn để tìm nhiều trường hợp của @mui/styles. Bạn chỉ có thể kiểm tra nguồn gói của mình hoặc sử dụng một công cụ như source-map-explorer hoặc webpack-bundle-analyzer .
Nếu bạn xác định rằng sự trùng lặp là vấn đề bạn đang gặp phải thì có một số cách bạn có thể thử để giải quyết:
Nếu bạn đang sử dụng npm, bạn có thể thử chạy npm dedupe. Lệnh này tìm kiếm các phụ thuộc cục bộ và cố gắng đơn giản hóa cấu trúc bằng cách di chuyển các phụ thuộc chung lên cao hơn trên cây.
Nếu bạn đang sử dụng Webpack, bạn có thể thay đổi cách giải quyết module @mui/styles. Bạn có thể ghi đè thứ tự mặc định mà Webpack sẽ tìm kiếm các dependency của bạn và làm cho ứng dụng của bạn node_modules được ưu tiên hơn thứ tự giải quyết module node mặc định:
resolve: {
+ alias: {
+ '@mui/styles': path.resolve(appFolder, 'node_modules', '@mui/styles'),
+ },
},
Sao chép
Chạy nhiều ứng dụng trên một trang
Nếu bạn có nhiều ứng dụng chạy trên một trang, hãy cân nhắc sử dụng một mô-đun @mui/styles cho tất cả các ứng dụng đó. Nếu bạn đang sử dụng Webpack, bạn có thể s ử dụng CommonsChunkPlugin để tạo một đoạn vendor rõ ràng , đoạn này sẽ chứa mô-đun @mui/styles:
module.exports = {
entry: {
+ vendor: ['@mui/styles'],
app1: './src/app.1.js',
app2: './src/app.2.js',
},
plugins: [
+ new webpack.optimize.CommonsChunkPlugin({
+ name: 'vendor',
+ minChunks: Infinity,
+ }),
]
}
Sao chép
[cũ] Tại sao các thành phần của tôi không hiển thị chính xác trong bản dựng sản xuất?
Lý do số 1 khiến điều này xảy ra có thể là do xung đột tên lớp khi mã của bạn nằm trong gói sản xuất. Để Material UI hoạt động, giá classNametrị của tất cả các thành phần trên một trang phải được tạo bởi một phiên bản duy nhất của trình tạo tên lớp .
Để khắc phục sự cố này, tất cả các thành phần trên trang cần được khởi tạo sao cho chỉ có một trình tạo tên lớp trong số chúng.
Bạn có thể vô tình sử dụng hai trình tạo tên lớp trong nhiều trường hợp khác nhau:
- Bạn vô tình đóng gói hai phiên bản của
@mui/styles. Có thể bạn có một phụ thuộc không thiết lập đúng Material UI là một phụ thuộc ngang hàng. - Bạn đang sử dụng
StylesProvidercho một tập hợp con của cây React của mình. - Bạn đang sử dụng một bundler và nó sẽ chia nhỏ mã theo cách khiến nhiều phiên bản trình tạo tên lớp được tạo ra.
Nếu bạn đang sử dụng Webpack với SplitChunksPlugin , hãy thử cấu hình cài đặt runtimeChunkbên dướioptimizations .
Nhìn chung, có thể dễ dàng khắc phục sự cố này bằng cách gói từng ứng dụng Material UI bằng StylesProvidercác thành phần ở đầu cây thành phần của chúng và sử dụng một trình tạo tên lớp duy nhất được chia sẻ giữa chúng .
[cũ] CSS chỉ hoạt động khi tải lần đầu và bị mất
CSS chỉ được tạo ra khi tải trang lần đầu tiên. Sau đó, CSS sẽ bị thiếu trên máy chủ cho các yêu cầu liên tiếp.
Hành động cần thực hiện
Giải pháp tạo kiểu dựa vào bộ nhớ đệm, trình quản lý trang tính , để chỉ đưa CSS một lần vào cho mỗi loại thành phần (nếu bạn sử dụng hai nút, bạn chỉ cần CSS của nút một lần). Bạn cần tạo một phiên bản mới sheetscho mỗi yêu cầu .
Ví dụ về cách sửa:
-// Create a sheets instance.
-const sheets = new ServerStyleSheets();
function handleRender(req, res) {
+ // Create a sheets instance.
+ const sheets = new ServerStyleSheets();
//…
// Render the component to a string.
const html = ReactDOMServer.renderToString(
Sao chép
[cũ] Tên lớp React không khớp với hydrat hóa
Prop className không khớp.
Có sự không khớp tên lớp giữa máy khách và máy chủ. Nó có thể hoạt động cho yêu cầu đầu tiên. Một triệu chứng khác là kiểu dáng thay đổi giữa lần tải trang ban đầu và quá trình tải xuống các tập lệnh máy khách.
Hành động cần thực hiện
Giá trị tên lớp dựa trên khái niệm về trình tạo tên lớp . Toàn bộ trang cần được hiển thị bằng một trình tạo duy nhất . Trình tạo này cần hoạt động giống hệt nhau trên máy chủ và trên máy khách. Ví dụ:
-
Bạn cần cung cấp một trình tạo tên lớp mới cho mỗi yêu cầu. Nhưng bạn không nên chia sẻ
createGenerateClassName()giữa các yêu cầu khác nhau:Ví dụ về cách sửa:
-// Create a new class name generator.
-const generateClassName = createGenerateClassName();
function handleRender(req, res) {
+ // Create a new class name generator.
+ const generateClassName = createGenerateClassName();
//…
// Render the component to a string.
const html = ReactDOMServer.renderToString(Sao chép
-
Bạn cần xác minh rằng máy khách và máy chủ của bạn đang chạy cùng một phiên bản Material UI. Có khả năng là sự không khớp của ngay cả các phiên bản nhỏ cũng có thể gây ra sự cố về kiểu dáng. Để kiểm tra số phiên bản, hãy chạy
npm list @mui/stylestrong môi trường mà bạn xây dựng ứng dụng và trong môi trường triển khai của bạn.Bạn cũng có thể đảm bảo cùng một phiên bản trong các môi trường khác nhau bằng cách chỉ định phiên bản Material UI cụ thể trong phần phụ thuộc của package.json.
ví dụ về bản sửa lỗi (package.json):
"dependencies": {
...
- "@mui/styles": "^5.0.0",
+ "@mui/styles": "5.0.0",
...
},Sao chép
-
Bạn cần đảm bảo rằng máy chủ và máy khách chia sẻ cùng một
process.env.NODE_ENVgiá trị.